aurora-article icon indicating copy to clipboard operation
aurora-article copied to clipboard

vue 实现图片不同加载方式

Open starryiu opened this issue 4 years ago • 0 comments

使用 vue 实现图片显示在视图时加载和图片按顺序加载两种方式,代码使用了 vue3 的新的组合式 api,代码较简单,可以稍微改进下。

首先是两种方式都要用到 CoverImage 组件

整个组件最重要的部分就是 loadImg 方法,这个方法用来加载图片,并当图片加载完成后显示该图片。

<template>
  <div>
    <img :src="imgSrc" v-show="visible" />
  </div>
</template>

<script>
import { ref } from 'vue'
export default {
  name: `CoverImage`,
  setup() {
    const imgSrc = ref(``)
    const visible = ref(false)
    const loadImg = function (src) {
      let img = new Image()
      img.src = src
      img.onload = img.onerror = () => {
        imgSrc.value = src
        visible.value = true
        this.$emit(`addLoadIndex`)
      }
    }
    return { imgSrc, visible, loadImg }
  },
}
</script>

图片显示在视图时加载

主要是利用js提供的 IntersectionObserver 对象来实现。

<template>
  <div>
    <div class="img-wrap" v-for="(src, index) in srcList" :key="index">
      <cover-image :ref="setItemRef" :eleIndex="index"></cover-image>
    </div>
  </div>
</template>

<script>
import { onBeforeUpdate, onMounted } from 'vue'

import CoverImage from './components/CoverImage'
export default {
	name: `CoverShowList`,
	components: {
		CoverImage
	},
	setup() {
		const srcList = [
			`https://i.postimg.cc/prGHDHk6/14.jpg`,
			`https://i.postimg.cc/tTzy4P6y/13.jpg`,
			`https://i.postimg.cc/YqDrF1sC/10.jpg`
		]
		let itemRefs = []
		let io = null
		const setItemRef = function (el) {
			itemRefs.push(el)
		}
		const getStatus = function (items) {
			items.map((item) => {
				if (!item.isIntersecting) return
				const eleIndex = item.target.getAttribute(`eleIndex`)
				itemRefs[eleIndex].loadImg(srcList[eleIndex])
				io.unobserve(item.target)
			})
		}
		onMounted(() => {
			io = new IntersectionObserver(getStatus)
			itemRefs.map((item) => {
				io.observe(item.$el)
			})
		})
		onBeforeUpdate(() => {
			itemRefs = []
		})
		return { srcList, setItemRef }
	}
}
</script>

<style>
.img-wrap {
  border: 1px solid red;
  padding: 400px 200px;
  margin-top: 200px;
}
.display-none {
  display: none;
}
</style>

图片按顺序加载

在父组件中设置一个 loadIndex 变量,然后用watch监听loadIndex的变化。

<template>
  <div>
    <div v-for="(item, i) in srcList" :key="i">
      <cover-image :ref="setItemRef" @addLoadIndex="addLoadIndex"></cover-image>
    </div>
  </div>
</template>

<script>
import { ref, watch, onMounted, onBeforeUpdate } from 'vue'

import CoverImage from './components/CoverImage'
export default {
	name: `CoverImageList`,
	components: {
		CoverImage
	},
	setup() {
		const srcList = [
			`https://i.postimg.cc/prGHDHk6/14.jpg`,
			`https://i.postimg.cc/tTzy4P6y/13.jpg`,
			`https://i.postimg.cc/YqDrF1sC/10.jpg`
		]
		let itemRefs = []
		const loadIndex = ref(0)
		const setItemRef = function (el) {
			itemRefs.push(el)
		}
		const addLoadIndex = function () {
			loadIndex.value++
		}
		onMounted(() => {
			itemRefs[loadIndex.value].loadImg(srcList[loadIndex.value])
		})
		onBeforeUpdate(() => {
			itemRefs = []
		})
		watch(loadIndex, (value) => {
			itemRefs[value] && itemRefs[value].loadImg(srcList[loadIndex.value])
		})
		return { loadIndex, srcList, setItemRef, addLoadIndex }
	}
}
</script>

starryiu avatar Mar 28 '21 07:03 starryiu