图片懒加载 LazyLoad

179 阅读5分钟

在现代网页开发中,优化页面性能是前端开发者的重要职责之一。而在优化网页加载速度和性能时,图片懒加载(LazyLoad)是一个非常有效的策略。本文将详细探讨图片懒加载的原理、浏览器的工作机制以及实现图片懒加载的方法和步骤。

浏览器会做什么?

当用户访问一个网页时,浏览器会执行一系列的步骤来渲染页面并显示给用户。具体流程如下:

  1. 渲染页面:浏览器首先开始渲染页面的内容。
  2. 下载解析HTML标签:浏览器下载并解析HTML文件,建立内存中的DOM树(例如,使用 document.querySelector 来选择DOM元素)。
  3. 下载CSS样式表:浏览器下载并解析CSS文件,生成渲染树。
  4. 合成DOM树和CSS渲染树:将DOM树和CSS渲染树结合起来生成最终的页面。

此外,JavaScript的执行是单线程的,而浏览器本身是多线程的。当页面中包含imglinkscript等标签时,浏览器会启动新的下载线程来并发处理这些资源。然而,同时下载过多的图片会导致资源的拥堵,就像在高速公路上发生堵车一样。那么问题来了:是否有必要同时并发下载那么多图片?

性能优化

为了提高页面的性能,我们通常采取以下几种策略:

  1. 首屏图片加载:优先加载用户首次看到的视窗中的图片,以便页面尽快显示出来。
  2. 滚动懒加载:当用户滚动到图片所在位置时才加载图片,从而减少初始加载的资源占用。
  3. 尽快显示页面:前端开发的基本任务是尽可能快地显示页面,让用户感觉页面加载速度更快。

具体实现

实现图片懒加载的具体步骤如下:

手动控制图片加载

通常情况下,直接在img标签中添加src属性会立刻触发图片下载。但在懒加载中,我们使用data-src等数据属性来存储图片的真实路径,然后通过JavaScript动态地设置src属性,从而实现图片的延迟加载。

  • 数据属性

在HTML5中,每个元素都可以有多个数据属性,通过dataset对象来访问这些属性。例如,使用data-src属性来存储图片的路径:

< img data-src="image.jpg" alt="Lazy Loaded Image">

比如说如果我们拿到下面一大串图片,该怎么处理呢?

 <img  data-price="20" data-src="https://img.36krcdn.com/20190808/v2_1565254363234_img_jpg">
    <img  data-src="https://img.36krcdn.com/20190905/v2_1567641293753_img_png">
    <img   data-src="https://img.36krcdn.com/20190905/v2_1567640518658_img_png">
    <img   data-src="https://img.36krcdn.com/20190905/v2_1567642423719_img_000">
    <img   data-src="https://img.36krcdn.com/20190905/v2_1567642425030_img_000">
    <img  data-src="https://img.36krcdn.com/20190905/v2_1567642425101_img_000">
    <img data-src="https://img.36krcdn.com/20190905/v2_1567642425061_img_000">
    <img  data-src="https://img.36krcdn.com/20190904/v2_1567591358070_img_jpg">
    <img  data-src="https://img.36krcdn.com/20190905/v2_1567641974410_img_000">
    <img  data-src="https://img.36krcdn.com/20190905/v2_1567641974454_img_000">

首先我们拿到img标签的HTMLCollection 对象,并获取img标签数量。接着添加一个事件监听器

const imgs = document.getElementsByTagName('img')
const num = imgs.length;
let n = 0
document.addEventListener('DOMContentLoaded',()=> {
    loadImage()
})

其中,DOMContentLoaded是一个事件,即DOM树加载完成后触发。

接下来我们再来写loadImage函数。

function loadImage(){
    let screenHeight = document.documentElement.clientHeight//一屏高度
    let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    for(let i = 0;i<num;i++){
        if(imgs[i].offsetTop < screenHeight + scrollTop){
            imgs[i].src = imgs[i].getAttribute('data-src')
            n = i + 1
            if(n===num){
                console.log('所有图片加载完成');
                window.removeEventListener('scroll',loadImage)
            }
        }
    }
}

解毒💊

1.let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

上面代码是用来获取当前网页的垂直滚动位置的,也就是页面相对于视口(viewport)向上滚动了多少像素。在不同的浏览器中,scrollTop 的实现可能存在于不同的对象上,因此我们可以通过逻辑或运算符 (||) 来兼容不同的情况。

  • document.documentElement.scrollTop:在大多数现代浏览器中,scrollTop 属性存在于 document.documentElement 上,即整个 HTML 文档的根元素。这通常指的是 <html> 元素。
  • document.body.scrollTop:在一些旧的浏览器中,尤其是 Internet Explorer,scrollTop 属性可能存在于 document.body 上。

所以,let scrollTop = document.documentElement.scrollTop || document.body.scrollTop; 这行代码会首先尝试从 document.documentElement 获取 scrollTop,如果它不存在或为 undefined,则会尝试从 document.body 获取。这样可以确保代码在各种浏览器中都能正确运行。

2.offsetTop

offsetTop 是一个属性,用于获取某个元素相对于其 offsetParent 的垂直位置(距离顶部的距离)。offsetParent 是最近的具有定位上下文(position 不为 static)的祖先元素,或者是元素本身如果它直接定位于 viewport。这里则是获取图片距离最顶部距离。

当一屏的高度(screenHeight) + 滚动的高度(scrollTop) > 某张图片距离最顶部的高度时(imgs[i].offsetTop),我们就将存储在data-src中的图片路径赋值给src。 说人话就是当用户屏幕可以看见那张图片的时候再把它加载出来。最后图片全部加载完后我们取消掉事件。

最后再提一嘴,我们可以用_.throttle节流方法来限制loadImages函数的调用频率,避免滚动事件过于频繁触发影响性能。_.throttle方法来自Lodash库。

 const throttleLayLoad = _.throttle(loadImage,300)
 window.addEventListener('scroll', throttleLayLoad)

总结

总的来说,图片懒加载不仅能够显著提高页面性能,还能让我们更深入地理解浏览器的工作机制和前端性能优化的策略。在实际项目中,结合具体业务场景,合理地实现和优化懒加载,可以为用户带来更好的浏览体验。