v-lazyImg
在 Vue 3 中,可以通过自定义指令来实现v-lazyImg 功能
- 新建一个名为 lazyImg.ts 的文件,在其中定义一个名为 lazyImg 的自定义指令。
import type { Directive, DirectiveBinding ,App} from 'vue'
import errorImg from './errorSrc.png'
let options: {root: HTMLElement | nullthreshold: number
} | null
let observer: IntersectionObserver | null = null
const callback: IntersectionObserverCallback = (entries) => {entries.forEach((entry) => {if (entry.isIntersecting) { const target = entry.target as HTMLImageElement let img = target.dataset.src || '' const loadImage = (url: string) => {const image = new Image() image.src = urlimage.onload = () => {console.log('图片加载成功'); target.src = urlobserver?.unobserve(target)}image.onerror = () => {target.src = errorImgobserver?.unobserve(target)console.log('图片加载失败')}}loadImage(img)}})
}
const observerHandler: (el: Element, binding: DirectiveBinding) => void = (el,binding,
) => {if (el.tagName !== 'IMG')returnconst { value } = binding el.setAttribute('data-src', String(value)) observer?.observe(el)
}
const vImgLazyLoad: Directive = {beforeUnmount(el: HTMLElement) {if (observer)observer.unobserve(el)},mounted(el: HTMLElement, binding:DirectiveBinding) {if (options === null) {options = {root: document.querySelector('html'), threshold: 0.1, }}if (observer === null) observer = new IntersectionObserver(callback, options)observerHandler(el, binding)},updated(el: HTMLElement, binding: DirectiveBinding) {observerHandler(el, binding)},
}
export const setupLazyImgDirective = (app: App<Element>) => {app.directive('lazyImg', vImgLazyLoad)}
export default vImgLazyLoad
- 在 main.ts 中导入directive/index.ts并注册指令。
import type { App } from 'vue'
import {setupLazyImgDirective} from './lazyImg'export const setupPermission = (app: App<Element>) => {setupLazyImgDirective(app)
}
<script setup lang="ts">import {ref} from "vue";const list = Array.from({ length: 100 }).map((_, i) => ({id: i,img: 'https://img1.baidu.com/it/u=837510728,3756639739&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800'}))
</script><template><imgv-for="item in list":key="item.id"v-lazyImg="item.img":style="{ width: '100px', height: '100px', display: 'block' }"/>
</template>