如何用JavaScript实现图片懒加载_交叉观察器怎么用

发布时间 - 2026-01-01 00:00:00    点击率:
IntersectionObserver 是浏览器原生异步回调机制,用于监听元素进入/离开视口,性能优于 scroll + getBoundingClientRect();它不触发强制同步布局,支持 root、threshold、rootMargin 配置,需处理加载失败、重复绑定、内存泄漏等问题,并在不支持时降级为节流 scroll + requestIdleCallback。

IntersectionObserver 是什么,为什么不用 getBoundingClientRect

它不是轮询检测,而是浏览器原生的异步回调机制,性能远好于 scroll + getBoundingClientRect()。尤其在长列表或滚动频繁的页面里,后者容易触发强制同步布局(Layout Thrashing),造成卡顿。

关键点:它只在元素进入/离开视口时才通知,且不阻塞主线程;而 getBoundingClientRect() 每次调用都可能触发重排。

基本用法:监听图片是否进入视口并加载

核心是创建一个 IntersectionObserver 实例,传入回调函数和配置项,再用 observe() 绑定目标 元素。

  • root:默认为浏览器视口;设为某个容器元素时,就以该容器为“视口”边界
  • threshold:0~1 的数组,表示目标元素多少比例进入 root 时触发回调(如 [0, 0.25, 0.5, 0.75, 1]
  • rootMargin:类似 CSS margin,可提前触发(如 "100px" 表示元素距离视口还有 100px 就开始加载)
const imgObserver = new IntersectionObserver(
  (entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        img.classList.remove('lazy');
        imgObserver.unobserve(img); // 加载完就停止监听
      }
    });
  },
  {
    rootMargin: '100px', // 提前加载,防滚动过快出现空白
    threshold: 0.1
  }
);

document.querySelectorAll('img.lazy').forEach(img => {
  imgObserver.observe(img);
});

常见坑:图片加载失败后没 fallback、重复绑定、未解绑

懒加载不是加个 src 就完事——网络异常、路径错误、CORS 都会让 img 显示为空白,且 IntersectionObserver 不会二次触发。

  • 务必监听 img.onerror,降级显示占位图或提示文字
  • 避免对同一张图多次 observe()(比如组件重复渲染时没清理旧 observer)
  • unobserve() 要及时调用;否则即使图片已加载,observer 仍持有引用,影响内存回收
  • 服务端返回的 HTML 若含 src,要确保它为空或为占位图,否则浏览器会提前发起请求,失去懒加载意义

兼容性与降级方案:Safari 12.1+ 和 IE 完全不支持

如果必须支持 Safari 12 或更早版本,不能直接用 IntersectionObserver。可用 scroll + requestIdleCallback 组合做轻量降级,但要注意节流。

简单判断:

if ('IntersectionObserver' in window) {
  // 使用 IntersectionObserver
} else {
  // 降级:监听 scroll,用 getBoundingClientRect + throttle
  // 注意:避免在回调中直接操作 DOM,优先用 requestIdleCallback 延后执行
}

真正麻烦的不是写降级逻辑,而是混合使用时容易漏掉 unobserve 或重复绑定;建议项目里统一抽象成一个 useLazyImage Hook 或工具函数,把判断、绑定、错误处理、清理全包进去。


# css  # javascript  # java  # html  # go  # 浏览器  # 回调函数  # 工具  # 懒加载  # ssl  # safari  # win 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: C++用Dijkstra(迪杰斯特拉)算法求最短路径  Python面向对象测试方法_mock解析【教程】  百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭  详解jQuery停止动画——stop()方法的使用  Laravel如何实现API版本控制_Laravel版本化API设计方案  如何快速搭建高效WAP手机网站?  Laravel怎么配置自定义表前缀_Laravel数据库迁移与Eloquent表名映射【步骤】  Laravel怎么创建控制器Controller_Laravel路由绑定与控制器逻辑编写【指南】  如何登录建站主机?访问步骤全解析  网站优化排名时,需要考虑哪些问题呢?  php在windows下怎么调试_phpwindows环境调试操作说明【操作】  如何注册花生壳免费域名并搭建个人网站?  如何快速选择适合个人网站的云服务器配置?  如何实现建站之星域名转发设置?  Laravel Eloquent:优雅地将关联模型字段扁平化到主模型中  Laravel怎么调用外部API_Laravel Http Client客户端使用  Android仿QQ列表左滑删除操作  如何快速查询网址的建站时间与历史轨迹?  phpredis提高消息队列的实时性方法(推荐)  Laravel如何发送系统通知?(Notification渠道示例)  如何快速搭建二级域名独立网站?  如何在自有机房高效搭建专业网站?  Laravel Pest测试框架怎么用_从PHPUnit转向Pest的Laravel测试教程  Python文件流缓冲机制_IO性能解析【教程】  车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?  高防网站服务器:DDoS防御与BGP线路的AI智能防护方案  制作旅游网站html,怎样注册旅游网站?  如何快速搭建FTP站点实现文件共享?  如何破解联通资金短缺导致的基站建设难题?  laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程  PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)  Laravel Blade模板引擎语法_Laravel Blade布局继承用法  手机软键盘弹出时影响布局的解决方法  如何快速配置高效服务器建站软件?  今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】  香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化  Linux系统命令中screen命令详解  如何在万网ECS上快速搭建专属网站?  Laravel如何操作JSON类型的数据库字段?(Eloquent示例)  实现点击下箭头变上箭头来回切换的两种方法【推荐】  如何正确选择百度移动适配建站域名?  Laravel Sail是什么_基于Docker的Laravel本地开发环境Sail入门  Firefox Developer Edition开发者版本入口  动图在线制作网站有哪些,滑动动图图集怎么做?  网站制作软件免费下载安装,有哪些免费下载的软件网站?  深圳防火门网站制作公司,深圳中天明防火门怎么编码?  HTML透明颜色代码在Angular里怎么设置_Angular透明颜色使用指南【详解】  如何在万网利用已有域名快速建站?  Laravel如何实现API版本控制_Laravel API版本化路由设计策略  Android使用GridView实现日历的简单功能