图片懒加载是前端性能优化的重要手段,核心思路是只加载可视区域内的图片,当图片进入视口时再去请求加载,能有效减少页面初始加载的资源请求数量。在 Vue 项目中,有两种主流实现方式:基于原生
IntersectionObserver 的手动实现、使用成熟的第三方插件(如 vue-lazyload)。方式一:使用 vue-lazyload 插件(推荐,开箱即用)
这是 Vue 项目中最常用的懒加载方案,配置简单、兼容性好,还支持加载占位图、失败占位图等实用功能。
步骤 1:安装插件
bash
运行
# npm 安装
npm install vue-lazyload --save
# yarn 安装
yarn add vue-lazyload
步骤 2:在项目入口文件(main.js)中配置
javascript
运行
import Vue from 'vue'
import VueLazyload from 'vue-lazyload'
// 全局注册并配置懒加载
Vue.use(VueLazyload, {
preLoad: 1.3, // 提前加载距离视口1.3倍高度的图片
error: require('@/assets/images/error.png'), // 图片加载失败时显示的占位图
loading: require('@/assets/images/loading.gif'), // 图片加载中显示的占位图
attempt: 1, // 加载失败后重试次数
lazyComponent: true // 支持组件懒加载(可选)
})
步骤 3:在组件中使用
将图片的
src 属性替换为 v-lazy 即可:vue
<template>
<div class="image-list">
<!-- 普通图片懒加载 -->
<img v-lazy="item.imgUrl" alt="示例图片" v-for="item in imgList" :key="item.id" />
<!-- 背景图懒加载 -->
<div v-lazy:background-image="item.bgUrl" class="bg-box"></div>
</div>
</template>
<script>
export default {
data() {
return {
imgList: [
{ id: 1, imgUrl: 'https://example.com/img1.jpg', bgUrl: 'https://example.com/bg1.jpg' },
{ id: 2, imgUrl: 'https://example.com/img2.jpg', bgUrl: 'https://example.com/bg2.jpg' }
]
}
}
}
</script>
<style scoped>
.image-list {
display: flex;
flex-direction: column;
gap: 20px;
}
img {
width: 100%;
height: 300px;
object-fit: cover;
}
.bg-box {
width: 100%;
height: 300px;
background-size: cover;
}
</style>
方式二:手动实现(基于原生 IntersectionObserver)
如果不想引入第三方插件,可基于浏览器原生的
IntersectionObserver API 手动实现,适合对包体积有严格要求的场景。实现一个懒加载指令
javascript
运行
// 在 src/directives/lazyLoad.js 中定义指令
export default {
bind(el, binding) {
// 保存图片真实地址
const imgSrc = binding.value
// 初始化占位图(可选)
el.src = 'https://example.com/loading.png'
// 创建观察器实例
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
// 当图片进入视口
if (entry.isIntersecting) {
// 加载真实图片
el.src = imgSrc
// 加载完成后停止观察
observer.unobserve(el)
// 图片加载失败处理
el.onerror = () => {
el.src = 'https://example.com/error.png'
}
}
})
})
// 观察当前图片元素
observer.observe(el)
},
// 指令解绑时停止观察,防止内存泄漏
unbind(el) {
const observer = new IntersectionObserver(() => {})
observer.unobserve(el)
}
}
注册并使用指令
javascript
运行
// main.js 中全局注册指令
import Vue from 'vue'
import lazyLoad from '@/directives/lazyLoad'
Vue.directive('lazy', lazyLoad)
vue
<template>
<div>
<!-- 使用自定义懒加载指令 -->
<img v-lazy="item.imgUrl" alt="示例图片" v-for="item in imgList" :key="item.id" />
</div>
</template>
<script>
export default {
data() {
return {
imgList: [
{ id: 1, imgUrl: 'https://example.com/img1.jpg' },
{ id: 2, imgUrl: 'https://example.com/img2.jpg' }
]
}
}
}
</script>
兼容性说明
vue-lazyload:内部做了兼容性处理,支持 IE9+ 等低版本浏览器。IntersectionObserver:IE 浏览器不支持,如需兼容 IE,需引入 polyfill:bash运行npm install intersection-observer --save然后在入口文件引入:
javascript运行import 'intersection-observer'
总结
- 推荐方案:优先使用
vue-lazyload插件,配置简单、功能完善,适合大多数 Vue 2 项目。 - 轻量方案:基于
IntersectionObserver手动实现指令,无第三方依赖,适合对包体积敏感的场景。 - 核心逻辑:无论是插件还是手动实现,核心都是「监听图片元素是否进入视口,进入后再加载真实图片」,同时注意处理加载失败、内存泄漏等边界情况。