vue3实现v-lazy图片懒加载
困顿小狗 人气:3前置知识
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 对象代表嵌入的图像。
- onload 当图像装载完毕时调用的回调函数。
思路
想要的效果 在有多个图片加载的时候 只要在最外面的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); }, };
参考链接:
总结
加载全部内容