[封装自己的ui组件] 图片懒加载

99 阅读2分钟

问题

今天在开发组件库的过程中涉及到了图片懒加载,自己查询后也实现了功能

引用

需要先了解一个api IntersectionObserver

它可以监听一个元素是否与另一个元素出现交集(接触),体现在图片懒加载中就是目标图片是否将接触展示元素

效果.png

  • 实例化
let imgObserver = new IntersectionObserver(()=>{});

// imgObserver 属性
// observer() 给目标元素添加监视
// unobserve() 停止监听元素
// takeRecords() 返回所有监视的元素数组
// disconnect() 停止监听所有元素

通过new的方式可以创建一个空的监视器(imgServer)

  • 对元素创建监视
// 获取监视的目标元素 --- 这里监视图片组
let imgs = document

let imgObserver = new IntersectionObserver(callback, options);

// 循环给每个图片添加监视
imgs.forEach(item => {
    imgObserver.observer(item)
})

实例时接受一个回调函数,函数接受一个参数 ,此回调函数在监视元素位置改变时触发

  • callback 回调函数
let imgObserver = new IntersectionObserver((entries)=>{
    // entries 保存了监视的元素组(数组)
    // 每个 元素都有一下几个属性
    // target: 监视的目标元素
    // isIntersecting : 当监视元素出现在可视区域则值为true, 监视元素离开可视区则值为false
    // time: 返回一个记录从 IntersectionObserver 的时间原点到交叉被触发的时间的时间戳
    // intersectionRect: 用来描述root和目标元素的相交区域
    // intersectionRatio: 返回目标元素出现在可视区的比例
    // boundingClientRect: 返回包含目标元素的边界信息,返回结果与element.getBoundingClientRect() 相同
    // rootBounds: 用来描述交叉区域观察者(intersection observer)中的根.
    
}, options);
  • 对每一个元素进行处理
let imgObserver = new IntersectionObserver((entries)=>{
     entries.forEach(item => {
         // 当监视元素出现可视区
         if(item.isIntersecting){
             // 处理 --- 具体到懒加载就是 替换src
             item.target.src = item.target.dataset.src;
             
             // 完成后 取消当前监视元素的监视
             imgObserver.unobserver(item.target)
         }
     })
}
  • options
let imgObserver = new IntersectionObserver((entries, {
    root: // 监视的根元素, 即可视元素, 默认为html元素
    rootMargin: // 计算交叉时添加到**根(root)**边界盒[bounding box](https://link.juejin.cn/?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FGlossary%2Fbounding_box "https://developer.mozilla.org/en-US/docs/Glossary/bounding_box")的矩形偏移量, 可以有效的缩小或扩大根的判定范围从而满足计算需要。所有的偏移量均可用**像素**(`px`)或**百分比**(`%`)来表达, 默认值为"0px 0px 0px 0px"。
    threshold: // 一个包含阈值的列表, 按升序排列, 列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。当监听对象的任何阈值被越过时,都会触发callback。默认值为0。
})=>{}

思路

因为img标签的src一旦赋值就会请求图片地址,所以不能直接图片地址给到src,可先将图片地址都给到每一个图片元素的data-src上,当图片移动到可视区时就将这个可视元素的data-src给到src上就可以了

结合组件库实现

        // 懒加载功能   
        withLazy(bool) {
            // 判断是否有lazy 有--触发懒加载
            if (bool) {
                this.$nextTick(() => {
                    // 创建监听视口
                    let imgObserve = new IntersectionObserver((entries) => {

                        // 判断监听元素是否位于视口中间
                        if (entries[0].isIntersecting) {
                            // 获取交集对象
                            let tarImg = entries[0].target
                            // 赋值加载url
                            tarImg.src = tarImg.dataset.src;
                            // 接触监视元素
                            // imgObserve.unobserve(tarImg)
                            // 卸载监视器对象
                            imgObserve.disconnect();
                        }
                    },{
                        root: this.$props.scrollContainer
                    })
                    // 监视图片
                    imgObserve.observe(this.$refs.img)
                })
            } else {
            
            // 没有 则直接加载
                this.$nextTick(() => {
                    this.$refs.img.src = this.commSrc
                })
            }

效果

QQ录屏20221030183745.gif