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

JavaScript 图片懒加载实现指南

图片懒加载是一种常用的前端性能优化技术,其核心思想是仅当图片即将进入用户可视区域时才开始加载,而不是一次性加载页面中的所有图片。这有助于显著减少初始页面加载带宽、降低服务器压力,并提升用户体验。在 JavaScript 中,实现图片懒加载主要有两种主流方式:基于传统的 scroll 事件监听与元素位置计算,以及基于现代浏览器提供的 Intersection Observer API。

传统方法:使用 scroll 事件

传统的懒加载实现依赖于监听页面的 scrollresize 事件,并实时计算图片元素相对于视口的位置。通常,我们会将图片的真实地址存储在 data-src 自定义属性中,而不是直接写在 src 属性里。当图片的位置距离顶部小于视口高度与滚动偏移量之和时,才将 data-src 的值赋给 src 并触发加载。

<!DOCTYPE html>
<html>
<head>
    <style>
        img {
            display: block;
            width: 400px;
            height: 400px;
            margin-bottom: 800px;
            background: #eee; /* 占位背景色 */
        }
    </style>
</head>
<body>
    <img class="lazy-load" data-src="https://ippipp.com/400x400?text=Image+1" alt="懒加载图片1">
    <img class="lazy-load" data-src="https://ippipp.com/400x400?text=Image+2" alt="懒加载图片2">
    <img class="lazy-load" data-src="https://ippipp.com/400x400?text=Image+3" alt="懒加载图片3">

    <script>
        // 获取所有需要懒加载的图片
        const lazyImages = document.querySelectorAll(&#x27;.lazy-load&#x27;);

        // 判断元素是否进入视口
        function isElementInViewport(el) {
            const rect = el.getBoundingClientRect();
            return (
                rect.top >= 0 &&
                rect.left >= 0 &&
                rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
                rect.right <= (window.innerWidth || document.documentElement.clientWidth)
            );
        }

        // 加载可见的图片
        function lazyLoad() {
            lazyImages.forEach(img => {
                // 如果图片已加载,跳过
                if (img.classList.contains(&#x27;loaded&#x27;)) {
                    return;
                }
                // 如果图片进入视口,则加载
                if (isElementInViewport(img)) {
                    img.src = img.dataset.src;
                    img.classList.add(&#x27;loaded&#x27;);
                    img.classList.remove(&#x27;lazy-load&#x27;);
                }
            });
            // 如果所有图片都已加载,移除事件监听以节省性能
            if (document.querySelectorAll(&#x27;.lazy-load&#x27;).length === 0) {
                document.removeEventListener(&#x27;scroll&#x27;, lazyLoad);
                window.removeEventListener(&#x27;resize&#x27;, lazyLoad);
                window.removeEventListener(&#x27;orientationchange&#x27;, lazyLoad);
            }
        }

        // 初始检查并绑定事件
        lazyLoad();
        document.addEventListener(&#x27;scroll&#x27;, lazyLoad);
        window.addEventListener(&#x27;resize&#x27;, lazyLoad);
        window.addEventListener(&#x27;orientationchange&#x27;, lazyLoad);
    </script>
</body>
</html>

上述代码展示了 scroll 事件方法的完整实现。我们首先定义了一个 isElementInViewport 函数,它通过 getBoundingClientRect() 获取元素的大小及其相对于视口的位置,并判断元素是否完全可见。在 lazyLoad 函数中,我们遍历所有待加载的图片,检查其是否进入视口。一旦进入,则将其 data-src 属性值赋给 src,并通过添加 loaded 类标记已加载状态。最后,我们通过事件监听持续跟踪滚动、窗口尺寸变化以及设备方向变化。

传统方法虽然兼容性极佳,但存在明显的性能问题。每次滚动或调整窗口大小时,都会触发大量的位置计算,如果页面中存在大量图片,频繁的 getBoundingClientRect 调用容易导致主线程阻塞,引发页面卡顿。此外,scroll 事件的触发频率很高,通常需要配合 requestAnimationFrame 或节流函数来优化。

现代方法:使用 Intersection Observer API

Intersection Observer API 是浏览器提供的一种更高效、更简洁的解决方案。它允许我们以异步方式观察目标元素与其祖先元素或顶级文档视口的交叉状态。当被观察的元素进入或离开视口时,浏览器会自动触发回调函数,无需我们手动计算位置或监听 scroll 事件。

<!DOCTYPE html>
<html>
<head>
    <style>
        img {
            display: block;
            width: 400px;
            height: 400px;
            margin-bottom: 800px;
            background: #f0f0f0;
        }
    </style>
</head>
<body>
    <img class="lazy-img" data-src="https://ippipp.com/400x400?text=Intersection+1" alt="现代懒加载1">
    <img class="lazy-img" data-src="https://ippipp.com/400x400?text=Intersection+2" alt="现代懒加载2">
    <img class="lazy-img" data-src="https://ippipp.com/400x400?text=Intersection+3" alt="现代懒加载3">

    <script>
        document.addEventListener(&#x27;DOMContentLoaded&#x27;, function() {
            const lazyImages = document.querySelectorAll(&#x27;.lazy-img&#x27;);

            // 创建 Intersection Observer 实例
            const observer = new IntersectionObserver(function(entries, observerInstance) {
                entries.forEach(entry => {
                    // 如果目标元素与视口相交
                    if (entry.isIntersecting) {
                        const img = entry.target;
                        // 将 data-src 的值赋给 src,触发图片加载
                        img.src = img.dataset.src;
                        // 图片加载完成后移除类名,并停止观察该元素
                        img.classList.remove(&#x27;lazy-img&#x27;);
                        img.classList.add(&#x27;loaded&#x27;);
                        observerInstance.unobserve(img);
                    }
                });
            }, {
                // rootMargin: '0px 0px 50px 0px', // 可选的偏移量,提前加载
                // threshold: 0.01 // 可选的交叉比例阈值
            });

            // 开始观察每张图片
            lazyImages.forEach(img => {
                observer.observe(img);
            });
        });
    </script>
</body>
</html>

在这个 Intersection Observer 实现的示例中,我们首先在 DOMContentLoaded 事件中获取所有待加载的图片。接着,创建一个 IntersectionObserver 实例,并传入一个回调函数。回调函数接收两个参数:一个 entries 数组和观察器本身的引用。在回调内部,我们遍历每一个 entry,检查其 isIntersecting 属性。如果该属性为 true,说明图片至少有一部分已经进入视口。此时,我们将 data-src 赋给 src,更新 CSS 类名,并通过 unobserve 方法停止观察该元素,避免不必要的性能消耗。

此方法相较于传统方式有显著优势:它由浏览器底层实现,异步执行,不会阻塞主线程;无需手动监听 scroll 事件,大幅减少了事件处理器的数量;并且提供了 rootMarginthreshold 等配置项,允许开发者灵活控制“预加载”的触发时机。例如,设置 rootMargin: '100px 0px',可以使得图片在距离视口边缘还有 100 像素时就提前加载。

总结

综合来看,Intersection Observer API 是现代浏览器中实现图片懒加载的推荐方案。它在性能、代码简洁性和可维护性方面均优于传统的 scroll 事件方法。对于需要支持老旧浏览器的项目,可以继续使用 scroll 事件加节流处理的方案,或者引入 polyfill 来填补 Intersection Observer 的兼容性缺口。无论采用哪种方式,核心思想都是相同的:延迟加载非视口内的图片,只在需要时才发送网络请求,从而达到优化性能、节省流量的目的。

JavaScript图片懒加载Intersection_Observer_API性能优化scroll事件前端技术

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