Vue 自定义 v-lazy 指令通过 IntersectionObserver 实现图片懒加载,进入视口前100px预加载,支持占位图、错误回退、CSS状态控制;兼容性降级用节流 scroll + getBoundingClientRect;扩展支持 picture、背景图及响应式,需设宽高防抖动。

用 Vue 自定义指令实现图片懒加载,核心是让图片只在进入视口时才加载真实资源,避免首屏阻塞。不靠第三方插件,也能写出轻量、可控、兼容性好的 v-lazy 指令。
用 IntersectionObserver 判断可见性(现代推荐)
比起监听 scroll + getBoundingClientRect 手动计算,IntersectionObserver 性能更好、代码更干净:
- 创建观察器时设置 rootMargin: '0px 0px 100px 0px',让图片在进入视口前 100px 就开始加载,滚动快也不留白
- 每个 img 只 observe 一次,加载完成后调用 unobserve,防止重复触发
- 注意兼容性:IE 不支持,需降级处理(见下文)
管理图片加载生命周期(关键细节)
指令要接管从占位→加载→完成/失败的全过程:
- 真实地址存在 data-src 属性里,src 初始为空或设为 base64 占位图
- 可见后把 data-src 赋给 src,并移除 data-src,避免重复加载
- 可绑定 v-bind:class="{ 'is-loading': !loaded, 'is-loaded': loaded }",配合 CSS 实现淡入、骨架屏或错误 fallback
- 加载失败时,建议回退到默认图或显示提示,提升容错体验
兼容旧浏览器(scroll + 节流降级)
当 IntersectionObserver 不可用时,回退到 scroll 监听方案:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
立即学习“前端免费学习笔记(深入)”;
- 用 getBoundingClientRect() 获取元素相对视口位置,判断 top < windowHeight 是否成立
- 必须加 节流(如 debounce 300ms),否则滚动时高频触发影响性能
- 首次插入即执行一次 load,避免页面初始就位于目标区域却未加载
- 可引入 polyfill(如 intersection-observer),比手写降级更省心
扩展支持多种图片场景
实际项目不止有 <img>,还需覆盖响应式与背景图:
- 对 <picture> 元素,遍历内部 <source> 标签,把 data-srcset → srcset、data-media → media
- 对背景图,用 el.style.backgroundImage = `url("${src}")` 设置,注意引号和 URL 编码
- 通过修饰符控制行为,例如 v-lazy:bg 表示背景图模式,v-lazy:responsive 启用 srcset 支持
- 首屏关键图(如 logo、banner)建议不加 v-lazy,直接加载保证核心内容优先
记得给懒加载图片设置固定宽高或 aspect-ratio,防止加载完成时布局抖动。这套方案落地后,首屏时间通常减少 20%~40%,用户感知明显。

















