前置知识
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); }, };
参考链接:
总结
到此这篇关于vue3组合式api实现v-lazy图片懒加载的文章就介绍到这了,更多相关vue3实现v-lazy图片懒加载内容请搜索阿兔在线工具以前的文章或继续浏览下面的相关文章希望大家以后多多支持阿兔在线工具!