前置知识
Intersection Observer
浏览器提供api,用于检测目标元素和祖先元素/顶级文档视窗 (viewport) 交叉状态的方法。
const observer = new IntersectionObserver(function (IntersectionObserverEntry) {},options); observer.observe(el);
构造函数接收一个回调函数,一个配置对象(可选),返回一个观察器实例。实例的observe方法接收一个dom节点作为观察的对象
当目标对象出现在视口的时候,会调用回调函数,传递一个元素都为IntersectionObserverEntry
对象的数组。
IntersectionObserverEntry
对象有以下属性 (只列举了这篇用到的两个):
- target:被观察的目标元素,是一个 DOM 节点对象
- intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
Vue3指令周期
- created:在绑定元素的 attribute 或事件监听器被应用之前调用;
- beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用;
- mounted:在绑定元素的父组件被挂载后调用;
- beforeUpdate:在更新包含组件的 VNode 之前调用;
- updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用;
- beforeUnmount:在卸载绑定元素的父组件之前调用;
- unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次;
image对象
Image 对象代表嵌入的图像。
思路
想要的效果 在有多个图片加载的时候 只要在最外面的wrapper上用一次v-lazy就可以
每张图片的src先用加载gif替换掉,然后再放到文档碎片里面,等到用户滑动到视口了再挂载上图片元素,之前一直使用加载的gif占位,等图片加载完成再替换。
首先vue3的指令跟组件类似也有生命周期,created
的时候指令绑定的dom元素还没有attribute,也没有DOM结构,所以不适合,mounted
整个DOM元素已经挂载到页面上了,图片在挂载上去的时候就开始加载,再做懒加载已经没有意义了,所以使用beforeMount
,有完整的DOM结构,但是没有挂载到页面上。
完整代码
export const lazyLoad = { beforeMount(el: any,binding: any,vnode: any,prevVnode: any) { const img = el.querySelector(`.${el.className} img`); const src = img.getAttribute("src"); // 图片使用loading gif替换 img.setAttribute("src","https://m.tea7.com/images/imgLoading.gif"); // 新建Image对象 const tempImg = new Image(); tempImg.onload = function () { img.setAttribute("src",src); }; const parent = img.parentNode; const observer = new IntersectionObserver(function (changes) { // 可视 changes.forEach((item) => { if (item.intersectionRatio !== 0) { tempImg.src = src; } }); }); observer.observe(el); },};
参考链接:
IntersectionObserver API 使用教程
总结
原文地址:https://blog.csdn.net/neversleepy/article/details/127020065
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。