vue3封装一个图片懒加载的自定义指令

功能介绍

利用IntersectionObserver API实现,主要功能

  1. 图片懒加载
  2. 传递一个回调函数,该回调函数会在图片出现时触发,并接收显示的元素。

代码展示

<template>
    <div class="test h-[4000px] bg-slate-400 ">
        <div class="wrapper flex flex-col mx-auto bg-neutral-200 h-full w-[500px] ">
            <img v-for="item of arr " v-load="{src:item,root:null,cb:loadDone}"  alt="风景图"/>
        </div>
    </div>
</template>

<script setup lang='ts'>
const loadDone = (el:HTMLElement) => {
    console.log(el,'执行回调')
}
const arr = [
    '../../../src/assets/scenery/scene1.jpg',
    '../../../src/assets/scenery/scene2.jpg',
    '../../../src/assets/scenery/scene3.jpg',
    '../../../src/assets/scenery/scene4.jpg',
    '../../../src/assets/scenery/scene5.jpg',
    '../../../src/assets/scenery/scene6.jpg',
    '../../../src/assets/scenery/scene6.jpg',
    '../../../src/assets/scenery/scene6.jpg',
    '../../../src/assets/scenery/scene6.jpg',
    '../../../src/assets/scenery/scene6.jpg',
    '../../../src/assets/scenery/scene6.jpg',
]
</script>

<style lang='scss' scoped>
 img{ width: 100%; height: 500px; }
</style>

let observe = false
var elementArr = [] as { el: HTMLElement, src: string, cb: Function | null; }[]
const options = {
    threshold: [0],//threshold:属性决定相交比例为多少时,触发回调函数。取值为 0 ~ 1,或者 0 ~ 1的数组。
    rootMargin: "0px",//rootMargin: 类似于 CSS 的 margin 属性。用来缩小或扩大 rootBounds,从而影响相交的触发 
    root: null,//root:设置监视器的根节点,不传则默认为视口。
}
const observers = new IntersectionObserver(isoCallback,options)
function useLoadDirective() {
    return {
        created(el:HTMLElement,binding:any,vnode:any) {
            elementArr.push({ el, src: binding.value.src,cb: binding.value.cb})
           
        },
        mounted(el:HTMLElement,binding:any) {
            if (!observe) {
                if(binding.value.root)options.root = binding.value.root
                startObserve()
                observe = true
            }
        },
        
    }
}
function isoCallback(entries:any) {
    entries.forEach((element:any,index:number) => {
        if (element.isIntersecting) {
            elementArr.forEach(e => {
                if (e.el == element.target) {
                    element.target.setAttribute('src', e.src)
                    e.cb && e.cb(element.target)
                }
            });
            observers.unobserve(element.target)
        }
    });
}
function startObserve() {
    elementArr.forEach(v => [
        observers.observe(v.el)
    ])
}
useLoadDirective.dName = 'load'
export default useLoadDirective

图片效果展示

你可能感兴趣的:(javascript,vue.js,前端)