封装全局指令
// 定义懒加载插件,当前文件路径src/directives/index.js
import { useIntersectionObserver } from '@vueuse/core'
export const lazyPlugin = {
install (app) {
// 懒加载指令逻辑
app.directive('img-lazy', {
mounted (el, binding) {
// el: 指令绑定的那个元素 img
// binding: binding.value 指令等于号后面绑定的表达式的值 图片url
console.log(el, binding.value)
const { stop } = useIntersectionObserver(
el,
([{ isIntersecting }]) => {
console.log(isIntersecting)
if (isIntersecting) {
// 进入视口区域
el.src = binding.value
//如果不想在图片资源懒加载完成后依然对其进行监听,则需要添加stop()方法
stop()
}
},
)
}
})
}
}
注册全局指令
// main.js文件内全局指令注册
import { directivePlugin } from '@/directives'
app.use(directivePlugin)
使用
<RouterLink to="/">
<img v-img-lazy="imgUrl" alt="">
</RouterLink>
useIntersectionObserver方法原理
IntersectionObserver
是一个用于识别当前目标元素与另一个元素(该另一元素是视口或元素)相交情况的API。通过判断元素与视口是否有交叉来替代监听滚动事件处理懒加载。因此它不需要监听滚动事件,可以让页面更加流畅。
使用IntersectionObserver需要创建一个实例,把待监听的元素传入其中,并定义一个回调函数(即为目标元素与视口或元素相交时被调用的函数)。当目标元素出现在视口中或与监视器容器相交时,回调函数将被调用。
<!-- 图片标签,添加 data-src 属性表示要进行懒加载的图片 -->
<img class="lazyload" data-src="image.png">
// 查询所有待懒加载的元素
const lazyImages = document.querySelectorAll('.lazyload');
// 配置项
let options = {
root: null,
rootMargin: '0px',
threshold: 0.1
};
// 回调函数
function handleIntersection(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
}
// 创建 IntersectionObserver 实例
const observer = new IntersectionObserver(handleIntersection, options);
// 监听每个待懒加载的图片元素
lazyImages.forEach(img => {
observer.observe(img);
});
上述代码中,我们首先查询所有待懒加载的图片元素,并定义一个 IntersectionObserver 实例 observer
。当目标元素出现在视口中或与监视器容器相交时,回调函数 handleIntersection
将被调用,并通过将 data-src
属性复制到 src
属性来完成懒加载,并最终解除对该图片元素的监听。
注意:创建实例后需要使用 observe()
方法将需要被监听的元素传递给它,可以一次性地监听多个元素。另外,如果没有任何图片元素需要被监听了,还需要使用 unobserve()
方法取消观察。