一、原生懒加载:最简方案
现代浏览器已广泛支持 loading="lazy" 属性,只需在 <img> 标签中添加即可自动实现懒加载。
- 优势:无需编写 JavaScript,浏览器自动处理加载时机,兼容性覆盖 93.7% 的用户。
- 使用示例:
<img src="placeholder.jpg" loading="lazy" data-src="real-image.jpg" alt="示例图片" width="300" height="200"> - 注意事项:
- 设置宽高:必须指定
width和height,避免布局抖动(CLS)。 - 首屏避免使用:首屏关键图片(如 LCP 元素)禁用此属性,防止影响加载优先级。
- 设置宽高:必须指定
二、使用第三方库 vue-lazyload(推荐)
vue-lazyload 是 Vue 生态中最常用的图片懒加载库,支持 Vue2 和 Vue3,提供了丰富的配置(如占位图、加载失败处理、过渡效果等)。
1. 安装依赖
# Vue2 项目
npm install vue-lazyload@1.3.3 # 1.x 版本适配 Vue2
# 或
yarn add vue-lazyload@1.3.3
# Vue3 项目
npm install vue-lazyload@3 # 3.x 版本适配 Vue3
# 或
yarn add vue-lazyload@3
2. 全局配置(main.js)
// Vue2 示例
import Vue from 'vue'
import App from './App.vue'
import VueLazyload from 'vue-lazyload'
// 配置懒加载
Vue.use(VueLazyload, {
preLoad: 1.3, // 预加载高度比例(1.3 表示提前加载视口 1.3 倍高度的图片)
error: require('@/assets/error.png'), // 加载失败时显示的图片
loading: require('@/assets/loading.gif'), // 加载中显示的占位图
attempt: 1, // 加载失败重试次数
throttleWait: 200 // 节流等待时间(毫秒)
})
new Vue({
render: h => h(App)
}).$mount('#app')
3. 组件中使用
在模板中,将 v-bind:src 替换为 v-lazy 指令:
<template>
<div class="image-list">
<!-- 普通图片 -->
<img
v-lazy="imageUrl"
alt="示例图片"
class="lazy-img"
>
<!-- 列表中的图片(如长列表) -->
<div v-for="(item, index) in imageList" :key="index">
<img
v-lazy="item.url"
:alt="item.alt"
v-lazy:error="item.errorUrl" <!-- 单独设置该图片的失败图 -->
v-lazy:loading="item.loadingUrl" <!-- 单独设置该图片的占位图 -->
>
</div>
</div>
</template>
<script>
export default {
data() {
return {
imageUrl: 'https://picsum.photos/800/600', // 实际图片地址
imageList: [
{ url: 'https://picsum.photos/800/601', alt: '图片1' },
{ url: 'https://picsum.photos/800/602', alt: '图片2' }
]
}
}
}
</script>
三、原生 API 实现(不依赖第三方库)
利用浏览器原生的 IntersectionObserver API 监听图片是否进入视口,手动控制图片加载。适用于对项目体积有严格要求的场景。
1. 实现原理
- 初始时,图片的
src或srcset设为占位图(或不设置),将真实地址存放在data-src(自定义属性)中。 - 通过
IntersectionObserver监听图片元素,当元素进入视口时,将data-src的值赋给src,触发图片加载。
2. Vue 自定义指令实现
创建一个全局自定义指令 v-lazy,封装懒加载逻辑:
// Vue2 示例(main.js)
import Vue from 'vue'
import App from './App.vue'
// 注册全局懒加载指令
Vue.directive('lazy', {
// 指令绑定到元素时触发
bind(el, binding) {
// 存储真实图片地址
el.dataset.src = binding.value
// 初始显示占位图(可选)
el.src = require('@/assets/placeholder.png')
},
// 元素插入 DOM 时触发
inserted(el) {
// 创建观察器实例
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
// 元素进入视口
if (entry.isIntersecting) {
// 获取真实图片地址
const src = el.dataset.src
if (src) {
// 设置 src 触发加载
el.src = src
// 加载完成后停止观察
observer.unobserve(el)
}
}
})
}, {
rootMargin: '100px 0px' // 提前 100px 加载
})
// 开始观察目标元素
observer.observe(el)
}
})
new Vue({
render: h => h(App)
}).$mount('#app')
3. 组件中使用自定义指令
<template>
<div class="image-list">
<!-- 使用自定义 v-lazy 指令 -->
<img
v-lazy="imageUrl"
alt="原生懒加载示例"
>
<!-- 列表图片 -->
<img
v-for="(item, index) in imageList"
:key="index"
v-lazy="item.url"
:alt="item.alt"
>
</div>
</template>
<script>
export default {
data() {
return {
imageUrl: 'https://picsum.photos/800/600',
imageList: [
{ url: 'https://picsum.photos/800/601', alt: '图片1' },
{ url: 'https://picsum.photos/800/602', alt: '图片2' }
]
}
}
}
</script>
总结
图片懒加载是优化长列表或图片密集型页面的核心技术。实际开发中,推荐使用 vue-lazyload 快速实现,其丰富的配置能满足大多数需求;若项目对依赖体积有严格限制,可基于 IntersectionObserver 实现自定义懒加载指令。
1万+

被折叠的 条评论
为什么被折叠?



