查看: 177|回复: 0

Vue3图片懒加载Hooks封装与vue3-lazyload实践

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
在现代 Vue3 前端开发中,页面图片较多时,如果初始化阶段就加载全部图片,会拉长首屏时间并增加移动端流量消耗。图片懒加载的思路是:图片进入浏览器可视区域后,再把真实地址写入 src,从而减少初始请求量,让 HTML、CSS 等关键资源优先加载。本文围绕 Vue3 Hooks 封装,给出原生 IntersectionObserver 与 vue3-lazyload 库两种实现,并说明关键参数、调用逻辑和清理注意事项。

一、懒加载原理与目录准备
懒加载的本质不是一开始就请求所有图片,而是等图片进入可视区域再加载。实现时通常把真实图片地址放在 data-src,等条件满足后再赋值给 img.src。Vue3 中可以使用 IntersectionObserver 监听元素是否进入可视区。项目准备方面,在 src 下创建 hooks 文件夹,并新建 useLazyLoad.js。若要使用库方案,先安装 vue3-lazyload:
  1. npm install vue3-lazyload
复制代码

二、原生 Hooks 封装
原生方案不引入第三方库,直接利用 vue 的 ref、onMounted、onBeforeUnmount、nextTick 和浏览器 IntersectionObserver。完整示例:
  1. import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
  2. export default function useLazyLoad() {
  3. // 用于存储图片是否加载完成的响应式状态
  4. const isLoaded = ref(false);
  5. // 加载图片的函数
  6. const loadImage = (imgElement) => {
  7. if (!imgElement) return;
  8. const observer = new IntersectionObserver((entries) => {
  9. entries.forEach((entry) => {
  10. if (entry.isIntersecting) {
  11. const img = entry.target;
  12. img.src = img.dataset.src;
  13. isLoaded.value = true;
  14. observer.disconnect();
  15. }
  16. });
  17. });
  18. observer.observe(imgElement);
  19. };
  20. // 在组件挂载时执行的逻辑
  21. onMounted(() => {
  22. // 使用nextTick确保DOM更新完成后再获取图片元素
  23. nextTick(() => {
  24. const imgElements = document.querySelectorAll('img[data-src]');
  25. imgElements.forEach((img) => {
  26. loadImage(img);
  27. });
  28. });
  29. });
  30. // 在组件卸载前执行的逻辑
  31. onBeforeUnmount(() => {
  32. const observers = [];
  33. const imgElements = document.querySelectorAll('img[data-src]');
  34. imgElements.forEach((img) => {
  35. const observer = img.__observer;
  36. if (observer) {
  37. observers.push(observer);
  38. }
  39. });
  40. observers.forEach((observer) => {
  41. observer.disconnect();
  42. });
  43. });
  44. return {
  45. isLoaded
  46. };
  47. }
复制代码
代码逻辑说明:isLoaded 是一个响应式引用,用来跟踪图片是否已经加载完成。loadImage 接收图片元素,创建 IntersectionObserver 实例;当 entries 中的 entry.isIntersecting 为 true 时,说明图片进入可视区域,此时把 img.src 设置为 img.dataset.src,也就是 data-src 中保存的真实地址,并将 isLoaded 置为 true,然后调用 observer.disconnect() 断开该观察器。onMounted 在组件挂载时执行,内部用 nextTick 等待 DOM 更新完成,再通过 document.querySelectorAll('img[data-src]') 获取所有待懒加载图片,并逐个调用 loadImage。onBeforeUnmount 在组件卸载前执行,原示例尝试从 img.__observer 读取观察器并统一 disconnect,以避免内存泄漏。这里要注意:如果 loadImage 中没有把创建的 observer 保存到 img.__observer,那么卸载阶段的收集逻辑无法拿到实例;按该清理思路实现时,应在 observe 之后补上 img.__observer = observer 或在闭包中维护观察器集合。

三、使用 vue3-lazyload 库封装
库方案先执行 npm install vue3-lazyload,然后在 Hooks 中导入 lazyLoad。示例:
  1. import { ref, onMounted, onBeforeUnmount } from 'vue';
  2. import lazyLoad from 'vue3-lazyload';
  3. export default function useLazyLoad() {
  4. // 创建一个响应式的对象来存储图片加载状态
  5. const isLoaded = ref(false);
  6. // 定义加载图片的函数
  7. const loadImage = (imgElement) => {
  8. if (!imgElement) return;
  9. const observer = new IntersectionObserver((entries) => {
  10. entries.forEach((entry) => {
  11. if (entry.isIntersecting) {
  12. lazyLoad(entry.target);
  13. isLoaded.value = true;
  14. observer.disconnect();
  15. }
  16. });
  17. });
  18. observer.observe(imgElement);
  19. };
  20. // 在组件挂载时,绑定加载图片的事件
  21. onMounted(() => {
  22. const imgElements = document.querySelectorAll('img[data-src]');
  23. imgElements.forEach((img) => {
  24. loadImage(img);
  25. });
  26. });
  27. // 在组件卸载前,清除所有的观察器
  28. onBeforeUnmount(() => {
  29. const observers = [];
  30. const imgElements = document.querySelectorAll('img[data-src]');
  31. imgElements.forEach((img) => {
  32. const observer = img.__observer;
  33. if (observer) {
  34. observers.push(observer);
  35. }
  36. });
  37. observers.forEach((observer) => {
  38. observer.disconnect();
  39. });
  40. });
  41. return {
  42. isLoaded
  43. };
  44. }
复制代码
这版逻辑与原生方案相近:isLoaded 记录加载状态;loadImage 创建 IntersectionObserver,当 entry.isIntersecting 为 true 时调用 lazyLoad(entry.target),把目标图片交给 vue3-lazyload 处理,同时把 isLoaded 置为 true,并断开观察器。onMounted 中查询 img[data-src] 并逐个进入观察。onBeforeUnmount 中同样按 img.__observer 收集观察器并 disconnect,这里同样需要确保观察器实例被保存到元素上,否则清理逻辑不会按预期工作。

四、性能优化与验证
实现懒加载后,可以从几个方面优化:合理设置 IntersectionObserver 的阈值,避免过于频繁地检查图片是否进入可视区;对图片进行适当压缩,减少单张图片的数据量;结合 Chrome 开发者工具的性能面板评估懒加载效果,观察首屏请求和加载时机的变化。对于移动端或图片较多的页面,按需加载能减少不必要流量,并改善关键资源加载顺序。

五、总结
Vue3 图片懒加载可以通过自定义 Hooks 统一封装。原生方案依赖 IntersectionObserver 和 data-src,适合希望减少依赖的项目;vue3-lazyload 方案通过安装库并调用 lazyLoad 完成加载。两种方式都要关注观察器的创建、保存与断开,尤其是组件卸载前的清理,否则容易留下内存泄漏隐患。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-10 16:38 , Processed in 0.022128 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部