图片懒加载

java 复制代码
import 'intersection-observer'
// 引入默认图片
import baseImg from '@/views/basicData/staffManagement/assets/img/default.jpg'

let timer = null
const imgReloadLimitMap = {}

// 创建一个监听器

const observer = new IntersectionObserver((entries) => {
    // entries是所有被监听对象的集合
    for (let i = 0, len = entries.length; i < len; i++) {
        const entry = entries[i]

        if (entry.isIntersecting || entry.intersectionRatio > 0) {
            // 同一张图片加载失败后重新加载的限制次数,规避无限递归
            // 当被监听元素到临界值且未加载图片时触发。
            const imgSrc = entry.target.dataSrc

            !entry.target.isLoaded && showImage(entry.target, imgSrc, imgReloadLimitMap[imgSrc])
        }
    }
})

function showImage(el, imgSrc, limit) {
    const img = new Image()
    img.src = imgSrc
    img.onload = () => {
        el.src = imgSrc
        el.isLoaded = true

        // 加载成功,去除映射关系
        delete imgReloadLimitMap[imgSrc]
    }
    img.onerror = () => limit > 0 && showImage(el, imgSrc, --limit)
}
export default {
    // 这里用inserted和bind都行,因为IntersectionObserver时异步的,以防意外还是用inserted好一点
    // inserted和bind的区别在于inserted时元素已经插入页面,能够直接获取到dom元素的位置信息。
    inserted(el, { value: { src, limit } }, vnode) {
        clearTimeout(timer)
        // 初始化时展示默认图片
        el.src = baseImg
        // 将需要加载的图片地址绑定在dom上
        el.dataSrc = src
        observer.observe(el)
        // 初始化一张图片的重加载次数
        imgReloadLimitMap[src] = limit
        // 防抖,这里在组件卸载的时候停止监听
        const vm = vnode.context
        timer = setTimeout(() => {
            vm.$on('hook:beforeDestroy', () => {
                observer.disconnect()
            })
        }, 20)
    },
    // 图片更新触发
    update(el, { value: { src } }) {
        el.isLoaded = false
        el.dataSrc = src
    }
    // unbind不太好,会执行多次,改进一下用组件的beforeDestroy卸载
    // unbind(){
    //   // 停止监听
    //   observer.disconnect();
    // }
}


//用法
<div class="img-box" @click="handleImagePreview(scope.row.picture)">
     <img
         v-imgLazy="{ src: scope.row.picture, limit: 1 }"
         alt=""
         class="img-preview"
     />
 </div>

import imgLazy from '@/directive/imgLazy'

export default {
    components: {
        customField,
        tableBase
    },
    directives: {
        imgLazy
    },
}

这段代码实现了一个基于Intersection Observer API的懒加载功能,主要用于优化图片加载性能,仅当图片进入可视区域时才开始加载。代码中还包含了错误处理逻辑,允许图片在加载失败后重试一定次数。以下是该段代码的详细解析:

引入依赖: 首先引入了intersection-observer polyfill以确保在不支持该API的浏览器中也能正常工作,并导入了一个默认图片作为占位符。

定义变量:

timer: 用于防抖处理,在组件销毁前注册监听器解除方法。

imgReloadLimitMap: 存储每张图片重试加载的剩余次数,避免无限重试导致的性能问题。

创建Intersection Observer实例:

observer用于监听图片元素是否进入视口。当图片可见时,调用showImage尝试加载图片。

showImage函数:

创建一个新的Image对象并设置其src属性。

图片加载成功(onload)时,将图片实际地址赋给DOM元素的src,标记图片为已加载。

图片加载失败(onerror)时,若还有重试机会,则递减重试次数并递归调用自身尝试再次加载。

Vue指令定义:

inserted钩子: 在DOM元素插入页面后执行,设置默认图片、绑定实际图片地址至DOM元素的自定义属性dataSrc,初始化重试次数,并开始监听图片的可见性变化。

防抖处理: 确保在组件即将销毁前解除对observer的监听,防止内存泄漏。通过setTimeout实现简单的防抖逻辑,延迟注册组件销毁前的清理操作。

update钩子: 当绑定的图片地址发生变化时,重置图片的加载状态并更新dataSrc,以便重新检查和加载新图片。

注释说明:

指出可以通过inserted或bind钩子实现懒加载,但选择了inserted因为它能确保获取到准确的DOM位置信息。

注释提到了原本打算在unbind钩子中解除监听器,但最终采用更可靠的组件生命周期钩子beforeDestroy来处理。

整体而言,这段代码是一个较为完善的图片懒加载解决方案,结合了Intersection Observer API以提升用户体验和性能,同时考虑了错误处理和资源管理的细节。

相关推荐
可触的未来,发芽的智生7 分钟前
发现:认知的普适节律 发现思维的8次迭代量子
javascript·python·神经网络·程序人生·自然语言处理
BYSJMG1 小时前
计算机毕业设计选题推荐:基于大数据的肥胖风险分析与可视化系统详解
大数据·vue.js·数据挖掘·数据分析·课程设计
0思必得01 小时前
[Web自动化] Selenium处理文件上传和下载
前端·爬虫·python·selenium·自动化·web自动化
phltxy2 小时前
Vue3入门指南:从环境搭建到数据响应式,开启高效前端开发之旅
前端·javascript·vue.js
小飞大王6662 小时前
CSS基础知识
前端·css
Charlie_lll2 小时前
学习Three.js–风车星系
前端·three.js
代码游侠2 小时前
学习笔记——Linux内核与嵌入式开发1
linux·运维·前端·arm开发·单片机·嵌入式硬件·学习
玩电脑的辣条哥3 小时前
幽灵回复AI已回复但前端不显示的排查与修复
前端·人工智能
石去皿3 小时前
轻量级 Web 应用 —— 把一堆图片按指定频率直接拼成视频,零特效、零依赖、零命令行
前端·音视频
星夜落月3 小时前
Web-Check部署全攻略:打造个人网站监控与分析中心
运维·前端·网络