Vue自定义指令实现图片懒加载详解
指令介绍
图片懒加载是前端性能优化的常用手段之一,当图片进入浏览器可视区域时,才加载图片资源,避免页面初始加载时一次性加载过多图片导致的页面卡顿、加载速度缓慢等问题。
Vue允许开发者自定义指令,通过指令可以封装DOM操作逻辑,实现代码复用。接下来将使用Vue自定义指令、Intersection Observer API实现图片懒加载,包含完整代码和实现原理。
实现原理
本次实现主要依赖Vue自定义指令的生命周期钩子和浏览器原生的Intersection Observer API,核心流程如下:
-
指令挂载阶段:在指令绑定的图片元素(el)挂载到DOM时(mounted钩子),先保存图片的真实地址(el.src),然后清空src属性,避免初始加载图片。
-
创建观察者实例:通过IntersectionObserver构造函数创建观察者对象,该对象可以监听目标元素与可视区域的交集状态。
-
监听元素交集状态:当观察者检测到图片元素进入可视区域(isIntersecting为true)时,将之前保存的真实地址赋值给el.src,触发图片加载。
-
停止监听:图片加载后,调用observer.unobserve(el)停止对该图片元素的监听,避免重复触发逻辑,节省性能。
指令定义文件
在Vue项目中,可新建directives/lazyLoad.ts(TypeScript)或directives/lazyLoad.js(JavaScript)文件,编写如下代码:
// 以TypeScript为例,JavaScript可删除类型注解
export default {
// 元素挂载到DOM时执行
mounted(el: HTMLImageElement) {
// 保存图片真实地址
const imageSrc = el.src;
// 清空src,防止初始加载
el.src = "";
// 创建IntersectionObserver实例
const observer = new IntersectionObserver((entries) => {
// 解构获取第一个entry的交集状态
const [entry] = entries;
// 判断元素是否进入可视区域
if (entry.isIntersecting) {
// 加载图片
el.src = imageSrc;
el.onerror = () => {
// 可添加加载失败占位图逻辑
el.src = '<url>';
}
// 图片加载完成后停止观察,避免重复监听
observer.unobserve(el);
}
}, {
// 可选配置:根元素(默认视口)、根边距(扩大/缩小监听范围)、阈值
rootMargin: '0px 0px 100px 0px', // 提前100px进入可视区域时加载
threshold: 0.1
});
// 开始观察目标元素
observer.observe(el);
}
};
全局注册(main.ts/main.js)
import { createApp } from 'vue';
import App from '@/App.vue';
import lazyLoad from '@/directives/lazyLoad';
const app = createApp(App);
// 全局注册自定义指令,指令名可自定义,这里用"lazy"
app.directive('lazy', lazyLoad);
app.mount('#app');
局部注册(组件内)
<template>
<img v-lazy src="https://example.com/your-image.jpg" alt="示例图片">
</template>
<script setup lang="ts">
import lazyLoad from './directives/lazyLoad';
</script>
使用方法
指令注册完成后,在组件的模板中,给需要懒加载的图片元素添加v-lazy指令即可,使用方式与原生src属性一致:
<template>
<img v-lazy src="https://example.com/your-image.jpg" alt="示例图片">
</template>
IntersectionObserver配置项
在创建观察者实例时,可以加入第二个参数为配置对象,可根据需求调整:
-
root:监听的根元素,默认是视口(viewport),可指定为某个DOM元素(需是目标元素的祖先元素)。
-
rootMargin:根元素的边距,格式与CSS margin一致(如"0px 0px 100px 0px"),用于扩大或缩小监听的可视区域。设置为"0px 0px 100px 0px"时,图片在距离视口底部100px时就会触发加载,提升用户体验(避免滚动到图片位置才开始加载导致的空白)。
-
threshold:阈值,取值范围0-1,表示目标元素进入根元素可视区域的比例达到该值时触发回调。例如0.1表示目标元素10%进入可视区域时触发。
加载失败处理
代码中添加了el.onerror事件监听,当图片加载失败时,会停止观察者监听,并设置一张占位图,避免页面出现破碎图片图标,提升用户体验。可根据项目需求替换占位图地址。
占位图与过渡效果
通过CSS给未加载的图片(src为空)设置背景色或占位图,同时添加opacity过渡效果,使图片加载时更平滑,提升视觉体验。