Vue3 如何实现图片懒加载?其实一个 Intersection Observer 就搞定了
大家好,在当今图片密集的网络环境中,优化图片加载已成为前端开发的重要任务。今天我们分享一下怎么使用 Vue3 实现图片的懒加载功能。
什么是图片懒加载?
假如你打开一个有大量图片的页面,如果所有图片同时加载,会导致页面卡顿、流量浪费,特别是对于那些需要滚动才能看到的图片。
懒加载技术就是解决这个问题的方案,只有当图片进入或即将进入可视区域的时候,才加载它们。
效果预览:
完整示例代码可在文末获取
实现原理
我们的Vue3懒加载实现基于以下核心技术:
1. Intersection Observer API
这是现代浏览器提供的强大API,可以高效监听元素是否进入可视区域,而无需频繁计算元素位置,性能远优于传统的滚动监听方式。
// 创建观察器
observer.value = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) { // 元素进入可视区域
loadImage();
observer.value.unobserve(entry.target); // 加载后停止观察
}
});
}, {
rootMargin: '50px 0px', // 提前50px开始加载
threshold: 0.1 // 元素10%可见时触发
});
2. 组件化设计
我们将懒加载功能封装为独立的 LazyImage 组件,提高代码复用性和可维护性。
代码实现详解
组件模板结构
<div class="lazy-image-container" ref="container">
<img
v-if="isLoaded && !hasError"
:src="actualSrc"
:alt="alt"
class="lazy-image"
:style="{ opacity: imageOpacity }"
@load="onLoad"
@error="onError"
/>
<div v-else-if="hasError" class="image-placeholder">
<div class="error-message">图片加载失败</div>
<button @click="retryLoad" style="margin-top: 10px;">重试</button>
</div>
<div v-else class="image-placeholder">
<div class="spinner"></div>
<div>加载中...</div>
</div>
</div>
组件包含三种状态:
- 加载中:显示旋转加载动画
- 加载完成:显示实际图片,带有淡入效果
- 加载失败:显示错误信息和重试按钮
核心逻辑实现
状态管理
setup(props, { emit }) {
const isLoaded = ref(false); // 是否已加载
const hasError = ref(false); // 是否加载失败
const imageOpacity = ref(0); // 图片透明度(用于淡入效果)
const observer = ref(null); // Intersection Observer实例
const container = ref(null); // 容器DOM引用
const actualSrc = ref(''); // 实际图片地址
// ...
}
使用Vue3的Composition API,我们可以更清晰地组织代码逻辑。
图片加载控制
const loadImage = () => {
if (props.slowLoad) {
// 模拟慢速网络 - 延迟2秒加载
setTimeout(() => {
actualSrc.value = props.src;
isLoaded.value = true;
}, 2000);
} else {
// 正常加载
actualSrc.value = props.src;
isLoaded.value = true;
}
};
这个函数根据slowLoad属性决定是否模拟慢速网络,便于测试不同网络条件下的表现。
生命周期管理
onMounted(() => {
// 创建并启动Intersection Observer
observer.value = new IntersectionObserver((entries) => {
// 观察逻辑...
});
if (container.value) {
observer.value.observe(container.value);
}
});
onUnmounted(() => {
// 组件卸载时清理观察器
if (observer.value) {
observer.value.disconnect();
}
});
确保在组件销毁时正确清理资源,避免内存泄漏。
错误处理与重试机制
const onError = () => {
hasError.value = true;
emit('error'); // 向父组件发送错误事件
};
const retryLoad = () => {
hasError.value = false;
isLoaded.value = false;
// 重新触发观察
if (observer.value && container.value) {
observer.value.observe(container.value);
}
};
良好的错误处理机制可以提升用户体验,让用户在图片加载失败时有机会重试。
应用该组件
在主组件中使用懒加载
<div class="gallery">
<div
v-for="(image, index) in images"
:key="index"
class="image-card"
>
<lazy-image
:src="image.url"
:alt="image.title"
:slow-load="networkSlow"
@loaded="onImageLoaded"
@error="onImageError"
></lazy-image>
<div class="image-info">
<div class="image-title">{{ image.title }}</div>
<div class="image-description">{{ image.description }}</div>
</div>
</div>
</div>
功能控制与统计
我们的主组件提供了实用的控制功能:
- 添加更多图片:动态加载更多图片
- 重置图片:恢复初始状态
- 模拟网络速度:切换正常/慢速网络模式
- 加载统计:实时显示已加载和失败的图片数量
进一步优化
在实际项目中,还可以考虑以下优化:
- 图片压缩与格式选择:使用WebP等现代格式,减小文件体积
- 渐进式加载:先加载低质量预览图,再加载高清图
- 预加载关键图片:对首屏内的关键图片不使用懒加载
- 使用CDN加速:通过内容分发网络提高图片加载速度
Github示例代码:github.com/1344160559-…
总结
Vue3图片懒加载是一个简单但极其实用的优化技术。通过Intersection Observer API和Vue3的响应式系统,我们可以以少量代码实现高效的懒加载功能,显著提升页面性能和用户体验。
这个实现不仅适用于图片展示类网站,也可以应用于任何需要优化资源加载的Vue3项目。希望本文能帮助你理解和实现这一重要前端优化技术!
本文首发于公众号:程序员刘大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!
📌往期精彩
《SpringBoot+MySQL+Vue实现文件共享系统》