为什么需要懒加载

移动端页面图片多、列表长,首屏把所有资源一次性加载会严重拖慢 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 配置速查

选项默认值说明
preLoad1.3预加载高度比例,提前加载可视区外的一小段
error''加载失败时显示的图片
loading''加载中显示的占位图
attempt3加载失败后的最大重试次数
listenEventsscroll 等监听的事件列表,默认含 scroll / resize
lazyComponentfalse是否启用懒渲染组件
throttleWait0滚动事件节流间隔(毫秒)

实战建议

  • 长列表里的图片统一走 v-lazy,占位图建议用体积小的 SVG 或 base64,避免占位图本身拖慢首屏
  • 对 SEO 有要求的页面(如官网详情页)不要对首屏关键图使用懒加载,爬虫可能抓不到
  • 懒渲染组件配合 @show 事件做"进入视口再请求",能把请求数压到最低

总结

Lazyload 是 Vant 中投入产出比最高的性能优化组件之一:一行指令就能把图片加载推迟到真正需要时,再配合懒渲染组件把组件挂载和数据请求同样延迟,长页面在低端机上的流畅度会有肉眼可见的提升。

性能优化不是炫技,是把每一字节流量都花在用户真正看到的地方。