导读:本期聚焦于小伙伴创作的《HTML图片懒加载实现方法详解:基于IntersectionObserver与滚动监听的两种方案》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《HTML图片懒加载实现方法详解:基于IntersectionObserver与滚动监听的两种方案》有用,将其分享出去将是对创作者最好的鼓励。

HTML图片懒加载实现指南

在网页开发中,如果页面包含大量图片,一次性加载所有图片会消耗大量带宽,延长页面首屏渲染时间,影响用户体验。图片懒加载就是一种优化方案,它的核心思路是:只有当图片进入浏览器的可视区域时,才去加载对应的图片资源,从而减少不必要的网络请求,提升页面加载速度。

图片懒加载的核心实现思路

实现图片懒加载主要依赖以下几个关键点:

  • 给图片标签设置自定义属性(比如data-src)存放真实的图片地址,src属性先设置为占位图或者空值,避免提前发起图片请求。
  • 监听浏览器的滚动事件、窗口大小改变事件,或者利用浏览器提供的IntersectionObserver API,判断图片是否已经进入可视区域。
  • 当图片进入可视区域时,把自定义属性里的真实图片地址赋值给src属性,触发图片加载,同时可以移除对应的监听逻辑,避免重复判断。

基于IntersectionObserver的实现方案(推荐)

IntersectionObserver是浏览器原生提供的API,用于异步观察目标元素与祖先元素或顶级文档视口的交叉状态,不需要手动计算元素位置,性能比监听滚动事件更好,是目前实现懒加载的首选方案。

下面是完整的实现代码示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片懒加载示例</title>
    <style>
        /* 占位样式,模拟图片未加载时的占位区域 */
        .lazy-img {
            width: 300px;
            height: 200px;
            background-color: #f0f0f0;
            margin: 20px auto;
            display: block;
        }
        /* 图片加载完成后移除占位背景 */
        .lazy-img.loaded {
            background-color: transparent;
        }
    </style>
</head>
<body>
    <h3>向下滚动查看懒加载效果</h3>
    <p>页面下方有5张需要懒加载的图片,滚动到对应位置才会加载。</p>
    <!-- 占位内容,撑开页面高度,方便演示滚动效果 -->
    <div style="height: 800px;"></div>

    <!-- 懒加载图片,真实地址存在data-src中,src先放占位图 -->
    <img class="lazy-img" 
         src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" 
         data-src="https://cdn.ipipp.com/demo/img1.jpg" 
         alt="示例图片1">
    <img class="lazy-img" 
         src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" 
         data-src="https://cdn.ipipp.com/demo/img2.jpg" 
         alt="示例图片2">
    <img class="lazy-img" 
         src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" 
         data-src="https://cdn.ipipp.com/demo/img3.jpg" 
         alt="示例图片3">
    <img class="lazy-img" 
         src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" 
         data-src="https://cdn.ipipp.com/demo/img4.jpg" 
         alt="示例图片4">
    <img class="lazy-img" 
         src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" 
         data-src="https://cdn.ipipp.com/demo/img5.jpg" 
         alt="示例图片5">

    <div style="height: 800px;"></div>

    <script>
        // 获取所有需要懒加载的图片元素
        const lazyImages = document.querySelectorAll('.lazy-img');
        
        // 创建IntersectionObserver实例,配置回调和可选参数
        const observer = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                // 如果目标元素进入可视区域
                if (entry.isIntersecting) {
                    const img = entry.target;
                    // 将data-src里的真实地址赋值给src,触发图片加载
                    const realSrc = img.getAttribute('data-src');
                    if (realSrc) {
                        img.src = realSrc;
                        // 加载完成后移除占位样式
                        img.onload = () => {
                            img.classList.add('loaded');
                        };
                    }
                    // 图片开始加载后,不再观察该元素,避免重复触发
                    observer.unobserve(img);
                }
            });
        }, {
            // 提前100px触发加载,让图片有足够时间加载,提升体验
            rootMargin: '100px'
        });

        // 遍历所有懒加载图片,开始观察
        lazyImages.forEach(img => {
            observer.observe(img);
        });
    </script>
</body>
</html>

上面的代码中,我们首先给所有需要懒加载的图片添加了lazy-img类,src属性使用了一个1x1像素的透明占位图,真实图片地址存在data-src自定义属性中。然后创建IntersectionObserver实例,设置当图片进入可视区域前100px时就触发回调,在回调中把data-src的值赋给src,同时停止对该图片的观察,避免重复处理。

兼容旧浏览器的滚动监听实现方案

如果项目需要兼容不支持IntersectionObserver的旧浏览器(比如IE系列),可以使用监听滚动事件的方案,通过手动计算元素位置判断是否进入可视区域。

下面是滚动监听方案的代码示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>滚动监听懒加载示例</title>
    <style>
        .lazy-img {
            width: 300px;
            height: 200px;
            background-color: #f0f0f0;
            margin: 20px auto;
            display: block;
        }
        .lazy-img.loaded {
            background-color: transparent;
        }
    </style>
</head>
<body>
    <h3>向下滚动查看懒加载效果</h3>
    <p>兼容旧浏览器的懒加载实现,通过监听滚动事件判断图片位置。</p>
    <div style="height: 800px;"></div>

    <img class="lazy-img" 
         src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" 
         data-src="https://cdn.ipipp.com/demo/img1.jpg" 
         alt="示例图片1">
    <img class="lazy-img" 
         src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" 
         data-src="https://cdn.ipipp.com/demo/img2.jpg" 
         alt="示例图片2">
    <img class="lazy-img" 
         src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" 
         data-src="https://cdn.ipipp.com/demo/img3.jpg" 
         alt="示例图片3">

    <div style="height: 800px;"></div>

    <script>
        // 获取所有需要懒加载的图片
        const lazyImages = document.querySelectorAll('.lazy-img');
        // 节流变量,避免滚动事件触发过于频繁
        let isThrottle = false;

        // 判断图片是否进入可视区域的函数
        function isInViewport(element) {
            const rect = element.getBoundingClientRect();
            // 元素的底部位置大于0,且顶部位置小于窗口高度,说明进入可视区域
            return rect.bottom > 0 && rect.top < window.innerHeight;
        }

        // 加载进入可视区域的图片
        function loadLazyImages() {
            // 遍历所有未加载的图片
            lazyImages.forEach((img, index) => {
                // 如果图片已经加载过,跳过
                if (img.classList.contains('loaded')) return;
                // 判断图片是否进入可视区域
                if (isInViewport(img)) {
                    const realSrc = img.getAttribute('data-src');
                    if (realSrc) {
                        img.src = realSrc;
                        img.onload = () => {
                            img.classList.add('loaded');
                        };
                    }
                }
            });
            // 检查是否所有图片都已加载,是的话移除滚动监听
            const unloadedImages = document.querySelectorAll('.lazy-img:not(.loaded)');
            if (unloadedImages.length === 0) {
                window.removeEventListener('scroll', handleScroll);
                window.removeEventListener('resize', handleScroll);
            }
        }

        // 滚动事件处理函数,使用节流优化性能
        function handleScroll() {
            if (isThrottle) return;
            isThrottle = true;
            // 使用requestAnimationFrame在下一帧执行,避免频繁计算
            requestAnimationFrame(() => {
                loadLazyImages();
                isThrottle = false;
            });
        }

        // 初始执行一次,加载首屏已经在可视区域的图片
        loadLazyImages();

        // 监听滚动、窗口大小改变事件
        window.addEventListener('scroll', handleScroll);
        window.addEventListener('resize', handleScroll);
    </script>
</body>
</html>

这个方案中,我们通过getBoundingClientRect()方法获取图片相对于视口的位置,判断是否在可视区域内。为了避免滚动事件触发过于频繁导致性能问题,使用了节流逻辑,结合requestAnimationFrame控制执行频率。当所有图片都加载完成后,会移除滚动和 resize 事件监听,减少不必要的性能消耗。

两种方案的对比与选择

对比维度IntersectionObserver方案滚动监听方案
性能表现原生API异步执行,性能更好,不会阻塞主线程需要手动计算位置,频繁触发时可能消耗更多性能,需要额外做节流优化
浏览器兼容性支持现代浏览器,IE全系列不支持兼容性更好,几乎所有浏览器都支持
实现复杂度代码逻辑简单,不需要手动计算位置逻辑相对复杂,需要处理位置计算、事件节流、监听移除等
适用场景面向现代浏览器的项目,优先选择该方案需要兼容旧浏览器(如IE)的项目使用

注意事项

  • 占位图建议使用极小的透明图或者纯色背景,避免占位图本身过大影响加载速度。
  • 如果页面是动态插入图片的,需要给新插入的图片也添加对应的懒加载观察逻辑,避免动态图片无法触发懒加载。
  • 使用IntersectionObserver时,可以通过rootMargin参数设置提前加载的距离,比如设置为'200px',可以让图片在进入可视区域前200px就开始加载,避免用户滚动到图片位置时还需要等待加载。
  • 如果图片加载失败,可以添加错误处理的逻辑,比如显示加载失败的占位提示,提升用户体验。

HTML图片懒加载IntersectionObserver_API滚动监听前端性能优化data_src属性

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。