Vue3 如何实现图片懒加载?其实一个 Intersection Observer 就搞定了

作者:刘大华日期:2025/11/30

大家好,在当今图片密集的网络环境中,优化图片加载已成为前端开发的重要任务。今天我们分享一下怎么使用 Vue3 实现图片的懒加载功能。

什么是图片懒加载?

假如你打开一个有大量图片的页面,如果所有图片同时加载,会导致页面卡顿、流量浪费,特别是对于那些需要滚动才能看到的图片。

懒加载技术就是解决这个问题的方案,只有当图片进入或即将进入可视区域的时候,才加载它们

效果预览:

完整示例代码可在文末获取

实现原理

我们的Vue3懒加载实现基于以下核心技术:

1. Intersection Observer API

这是现代浏览器提供的强大API,可以高效监听元素是否进入可视区域,而无需频繁计算元素位置,性能远优于传统的滚动监听方式。

1// 创建观察器
2observer.value = new IntersectionObserver((entries) => {
3  entries.forEach(entry => {
4    if (entry.isIntersecting) { // 元素进入可视区域
5      loadImage();
6      observer.value.unobserve(entry.target); // 加载后停止观察
7    }
8  });
9}, {
10  rootMargin: '50px 0px', // 提前50px开始加载
11  threshold: 0.1 // 元素10%可见时触发
12});
13

2. 组件化设计

我们将懒加载功能封装为独立的 LazyImage 组件,提高代码复用性和可维护性。

代码实现详解

组件模板结构

1<div class="lazy-image-container" ref="container">
2  <img
3    v-if="isLoaded && !hasError"
4    :src="actualSrc"
5    :alt="alt"
6    class="lazy-image"
7    :style="{ opacity: imageOpacity }"
8    @load="onLoad"
9    @error="onError"
10  />
11  <div v-else-if="hasError" class="image-placeholder">
12    <div class="error-message">图片加载失败</div>
13    <button @click="retryLoad" style="margin-top: 10px;">重试</button>
14  </div>
15  <div v-else class="image-placeholder">
16    <div class="spinner"></div>
17    <div>加载中...</div>
18  </div>
19</div>
20

组件包含三种状态:

  • 加载中:显示旋转加载动画
  • 加载完成:显示实际图片,带有淡入效果
  • 加载失败:显示错误信息和重试按钮

核心逻辑实现

状态管理

1setup(props, { emit }) {
2  const isLoaded = ref(false);    // 是否已加载
3  const hasError = ref(false);    // 是否加载失败
4  const imageOpacity = ref(0);    // 图片透明度(用于淡入效果)
5  const observer = ref(null);     // Intersection Observer实例
6  const container = ref(null);    // 容器DOM引用
7  const actualSrc = ref('');      // 实际图片地址
8  // ...
9}
10

使用Vue3的Composition API,我们可以更清晰地组织代码逻辑。

图片加载控制

1const loadImage = () => {
2  if (props.slowLoad) {
3    // 模拟慢速网络 - 延迟2秒加载
4    setTimeout(() => {
5      actualSrc.value = props.src;
6      isLoaded.value = true;
7    }, 2000);
8  } else {
9    // 正常加载
10    actualSrc.value = props.src;
11    isLoaded.value = true;
12  }
13};
14

这个函数根据slowLoad属性决定是否模拟慢速网络,便于测试不同网络条件下的表现。

生命周期管理

1onMounted(() => {
2  // 创建并启动Intersection Observer
3  observer.value = new IntersectionObserver((entries) => {
4    // 观察逻辑...
5  });
6  
7  if (container.value) {
8    observer.value.observe(container.value);
9  }
10});
11
12onUnmounted(() => {
13  // 组件卸载时清理观察器
14  if (observer.value) {
15    observer.value.disconnect();
16  }
17});
18

确保在组件销毁时正确清理资源,避免内存泄漏。

错误处理与重试机制

1const onError = () => {
2  hasError.value = true;
3  emit('error'); // 向父组件发送错误事件
4};
5
6const retryLoad = () => {
7  hasError.value = false;
8  isLoaded.value = false;
9  // 重新触发观察
10  if (observer.value && container.value) {
11    observer.value.observe(container.value);
12  }
13};
14

良好的错误处理机制可以提升用户体验,让用户在图片加载失败时有机会重试。

应用该组件

在主组件中使用懒加载

1<div class="gallery">
2  <div 
3    v-for="(image, index) in images" 
4    :key="index" 
5    class="image-card"
6  >
7    <lazy-image
8      :src="image.url"
9      :alt="image.title"
10      :slow-load="networkSlow"
11      @loaded="onImageLoaded"
12      @error="onImageError"
13    ></lazy-image>
14    <div class="image-info">
15      <div class="image-title">{{ image.title }}</div>
16      <div class="image-description">{{ image.description }}</div>
17    </div>
18  </div>
19</div>
20

功能控制与统计

我们的主组件提供了实用的控制功能:

  • 添加更多图片:动态加载更多图片
  • 重置图片:恢复初始状态
  • 模拟网络速度:切换正常/慢速网络模式
  • 加载统计:实时显示已加载和失败的图片数量

进一步优化

在实际项目中,还可以考虑以下优化:

  1. 图片压缩与格式选择:使用WebP等现代格式,减小文件体积
  2. 渐进式加载:先加载低质量预览图,再加载高清图
  3. 预加载关键图片:对首屏内的关键图片不使用懒加载
  4. 使用CDN加速:通过内容分发网络提高图片加载速度

Github示例代码github.com/1344160559-…

总结

Vue3图片懒加载是一个简单但极其实用的优化技术。通过Intersection Observer API和Vue3的响应式系统,我们可以以少量代码实现高效的懒加载功能,显著提升页面性能和用户体验。

这个实现不仅适用于图片展示类网站,也可以应用于任何需要优化资源加载的Vue3项目。希望本文能帮助你理解和实现这一重要前端优化技术!

本文首发于公众号:程序员刘大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

《SpringBoot+MySQL+Vue实现文件共享系统》

《这20条SQL优化方案,让你的数据库查询速度提升10倍》

《SpringBoot 动态菜单权限系统设计的企业级解决方案》

《Vue3和Vue2的核心区别?很多开发者都没完全搞懂的10个细节》


Vue3 如何实现图片懒加载?其实一个 Intersection Observer 就搞定了》 是转载文章,点击查看原文


相关推荐


把常用 Prompt 做成 Skill 之后,我和 Claude Code 的配合效率直接翻了 3 倍
技术探索家2025/11/27

一个真实故事 去年10月,我手里有个React项目要重构,2000多行的上帝类,看着就头疼。每次让Claude Code帮我优化代码,我都要重复交代一遍: "记得用TypeScript严格模式" "API调用要加错误处理" "组件要符合单一职责原则" 复制粘贴这些要求,少说也得两三分钟。更烦的是,聊了十几轮之后,Claude Code经常会"忘记"我最初的要求,又开始写出不符合规范的代码。 直到我在文档里翻到了Skill功能。 试了一周后,我把那些重复的要求全封装成了几个skill文件。现在


基于华为开发者空间从0实现一个MCP Server
高校俱乐部2025/11/25

1 概述 1.1 案例介绍 MCP (Model Context Protocol) 是一个开放协议,用于标准化应用程序如何向 LLM 提供上下文。可以将 MCP 想象成 AI 应用程序的 USB-C 接口。就像 USB-C 为设备连接各种外设和配件提供标准化方式一样,MCP 为 AI 模型连接不同的数据源和工具提供了标准化的方式。 MCP 的核心遵循客户端-服务器架构,其中主机应用程序可以连接到多个服务器: {{{width="60%" height="auto"}}} - MCP 主机:


【Spring】Cookie和Session是什么
d***9352025/11/23

文章目录 回顾 Cookie理解 SessionCookie 和 Session 的区别 回顾 Cookie HTTP 协议自身是属于“无状态”协议 无状态:默认情况下,HTTP 协议的客户端和服务器之间的这次通信和下次通信之间没有直接的联系 但是在实际开发中,我们很多时候是需要知道请求之间的关联关系的 例如登录网站成功后,第二次访问的时候服务器就能知道该请求是否是已经登录过了 上述图片中的“令牌”通常就存储在 Cookie 字段中 比如去医院挂号: 看病之前先挂


Lua 的 dofile 函数
IMPYLH2025/11/21

Lua 的 dofile 函数 是用于加载并执行外部 Lua 脚本文件的核心函数之一。它的主要功能和工作原理如下: 基本功能 读取指定的 Lua 文件编译文件内容为字节码执行编译后的代码返回该文件中最后一个表达式的值 语法格式 dofile(filename) 其中 filename 是要加载的 Lua 文件路径(相对路径或绝对路径) 典型应用场景 模块化开发时加载子模块游戏开发中加载场景或关卡配置动态加载用户自定义脚本测试环境快速重载修改后的代码 与 require 的区别


Gemini 3 Pro 来了!一句话生成完整网站,AI编程能力断层领先
wwwzhouhui2025/11/19

前言 在AI大模型快速迭代的今天,各家厂商疯狂堆参数、拼算力,动不动就是参数翻倍,但日常用起来的感觉却大同小异。就在大家对"GPT-4.5级"、"性能提升30%"这些宣传话术感到麻木的时候,Google在2025年11月18日悄悄扔出了一个重磅炸弹——Gemini 3.0。 Gemini 3 Pro 是 Google DeepMind 推出的新一代旗舰模型,被官方定义为"世界上多模态理解能力最强的模型"。它不是简单的微调升级,而是从零开始在自家TPU芯片上训练的全新模型,采用稀疏混合专家架构(M


使用 Cursor & Claude 操作 Figma 画图
Keely402852025/11/18

版权声明:本文为博主原创文章,未经博主允许不得转载。 文章底部留言可联系作者。 一、背景 现在各种AI工具的普及让人眼花缭乱,大家都在拥抱AI,之前朋友推荐某音的一个小视频看到可以使用Cursor操作Figma自动画图感觉非常神奇,正好我 Claude和Cursor 都在使用,对有意思的工具做了一些尝试,现在总结下经验希望可以帮助大家。 二、Cursor 如何操作 Figma 1. 安装 Cursor Cursor 可以点击官网下载选择合适版本进行使用。新账号试用过后需要付费使用,具体使用方法


我在高职教STM32(新12)——STM32中断概览
南耿先生2025/11/17

新学期,又要给学生上 STM32 嵌入式课程了。这课上了多年了,一直用的都是标准库来开发,已经驾轻就熟了。人就是这样,有了自己熟悉的舒适圈,就很难做出改变,老师上课也是如此,排斥新课和不熟悉的内容。显然,STM32 的开发,HAL 库已是主流,自己其实也在使用,只不过更换库就意味着教学内容有很大变化,自己也就迟迟没有迈出调整这一步。现在,是时候做出变化了,笔者计划保持教学项目不变(图 1 所示),逐步将源码替换成 HAL 库。虽然不能一步到位,但会在备课期间逐步替换,自己就当再学习和巩固一遍。


openGauss实战:Python开发与AI向量数据库应用
倔强的石头_2025/11/16

引言 经过前两篇文章的铺垫,我们已经掌握了openGauss的部署安装和使用Data Studio进行可视化管理。现在,我们来到了本系列文章的终章,将目光聚焦于开发者最关心的环节——如何在应用程序中与openGauss进行交互,并探索其在AI领域的应用潜力。 本文将以目前最流行的编程语言之一Python为例,详细演示如何连接openGauss数据库,并围绕两个典型的业务场景——“用户管理系统”和“订单支付流程”,构建完整的CRUD(创建、读取、更新、删除)与事务处理代码示例。更进一步,我们将结合


🍵 Go Queryx 入门指南:让数据库操作像喝奶茶一样丝滑!
golang学习记2025/11/15

🎬 前言:为什么是 Queryx?—— 因为 bug 等不及你「运行时才发现」 想象一下这些经典场景: // 🚨 GORM 的“惊喜盲盒” db.Where("nmae = ?", "john").Find(&users) // 拼写错误?编译器:没问题 👌 // → 运行时:查不到数据?🤔 调试 2 小时:哦,`nmae` 少了个 `e` …… // 🧨 原生 SQL 的“类型彩票” rows, _ := db.Query("SELECT * FROM users WHERE


Python 编程实战 · 实用工具与库 — Flask 基础入门
程序员爱钓鱼2025/11/14

Flask 是 Python 生态中最灵活、最轻量的 Web 框架之一,非常适合快速构建接口、网站原型、后台服务等。它遵循 WSGI 标准,核心库极其简洁,但可以通过插件无限扩展。 1. Flask 基础概念 ✔ Flask 是什么? 一个 微框架(Micro Framework) 默认只提供核心组件:路由、请求处理、模板、调试器 需要什么功能就安装什么扩展(ORM、表单验证、JWT、数据库等) ✔ Flask 的优势 代码简洁、上手快 灵活度极高(不像 Django 那样有强约

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2025 聚合阅读