为什么需要懒加载
移动端页面图片多、列表长,首屏把所有资源一次性加载会严重拖慢 FCP 和流量消耗。Vant 提供了 Lazyload 懒加载指令,让图片进入可视区域才加载,同时支持组件的懒渲染,是长列表页面的标配优化手段。
两种能力
Lazyload 指令负责图片懒加载;LazyRender / 懒渲染组件负责"进入可视区才挂载组件",两者互补。
注册插件
Lazyload 是指令型插件,需要在应用入口全局注册:
javascript
main.js
import { createApp } from "vue";
import { Lazyload } from "vant";
import App from "./App.vue";
const app = createApp(App);
app.use(Lazyload, {
lazyComponent: true, // 开启懒渲染组件能力
preLoad: 1.3, // 预加载高度比例(可视高度的 1.3 倍)
attempt: 3, // 加载失败后最大重试次数
});
app.mount("#app");
图片懒加载基础用法
把 src 换成 v-lazy 指令即可,指令的值就是图片地址:
html
demo.vue
<template>
<!-- 基础用法:进入可视区域才加载 -->
<img v-for="img in imageList" :key="img" v-lazy="img" />
<!-- 配合 van-image 使用 -->
<van-image
v-for="item in goodsList"
:key="item.id"
width="100"
height="100"
v-lazy="item.cover"
/>
</template>
<script setup>
import { ref } from "vue";
const imageList = ref([
"https://cdn.example.com/pic-1.jpg",
"https://cdn.example.com/pic-2.jpg",
"https://cdn.example.com/pic-3.jpg",
]);
const goodsList = ref([]);
</script>
占位图与失败图
加载中显示 loading 占位图,加载失败显示 error 图,避免页面出现裂图:
javascript
main.js
app.use(Lazyload, {
loading: "https://cdn.example.com/loading-spin.svg",
error: "https://cdn.example.com/load-fail.svg",
});
背景图懒加载
给 v-lazy 加 background 修饰符,可以把懒加载对象换成容器的背景图:
html
banner.vue
<template>
<!-- 进入可视区域后才设置 background-image -->
<div v-lazy:background="bannerUrl" class="banner">
活动横幅
</div>
</template>
<style scoped>
.banner {
height: 160px;
background-size: cover;
background-position: center;
}
</style>
组件懒渲染
注册时开启 lazyComponent: true 后,可以用 v-lazy-component 包裹任意组件,进入可视区域才真正挂载,适合评论区、图表等渲染开销大的模块:
html
detail.vue
<template>
<article>正文内容...</article>
<lazy-component @show="onCommentShow">
<comment-list :article-id="id" />
</lazy-component>
</template>
<script setup>
const onCommentShow = () => {
// lazy-component 首次进入可视区时触发,适合在这里请求评论数据
console.log("评论区进入视口,开始加载评论");
};
</script>
滚动容器不是 window 怎么办
如果列表放在 overflow: auto 的局部容器里滚动,需要把容器传给 scrollListener,否则懒加载不会响应:
javascript
page.vue
import { ref, onMounted } from "vue";
const scrollBox = ref(null);
onMounted(() => {
// 指定滚动容器后重新收集监听
scrollBox.value.$el && scrollBox.value.$lazyload?.attach?.();
});
⚠️ 注意:Vue3 版本下更常见的做法是给滚动容器加
data-lazy-container 属性并重新初始化插件;如果项目里大量使用局部滚动,建议优先考虑把列表直接放到页面级滚动,减少心智负担。Lazyload 配置速查
| 选项 | 默认值 | 说明 |
|---|---|---|
| preLoad | 1.3 | 预加载高度比例,提前加载可视区外的一小段 |
| error | '' | 加载失败时显示的图片 |
| loading | '' | 加载中显示的占位图 |
| attempt | 3 | 加载失败后的最大重试次数 |
| listenEvents | scroll 等 | 监听的事件列表,默认含 scroll / resize |
| lazyComponent | false | 是否启用懒渲染组件 |
| throttleWait | 0 | 滚动事件节流间隔(毫秒) |
实战建议
- 长列表里的图片统一走 v-lazy,占位图建议用体积小的 SVG 或 base64,避免占位图本身拖慢首屏
- 对 SEO 有要求的页面(如官网详情页)不要对首屏关键图使用懒加载,爬虫可能抓不到
- 懒渲染组件配合
@show事件做"进入视口再请求",能把请求数压到最低
总结
Lazyload 是 Vant 中投入产出比最高的性能优化组件之一:一行指令就能把图片加载推迟到真正需要时,再配合懒渲染组件把组件挂载和数据请求同样延迟,长页面在低端机上的流畅度会有肉眼可见的提升。
性能优化不是炫技,是把每一字节流量都花在用户真正看到的地方。