在现代网页开发中,优化页面性能是前端开发者的重要职责之一。而在优化网页加载速度和性能时,图片懒加载(LazyLoad)是一个非常有效的策略。本文将详细探讨图片懒加载的原理、浏览器的工作机制以及实现图片懒加载的方法和步骤。
浏览器会做什么?
当用户访问一个网页时,浏览器会执行一系列的步骤来渲染页面并显示给用户。具体流程如下:
- 渲染页面:浏览器首先开始渲染页面的内容。
- 下载解析HTML标签:浏览器下载并解析HTML文件,建立内存中的DOM树(例如,使用
document.querySelector来选择DOM元素)。 - 下载CSS样式表:浏览器下载并解析CSS文件,生成渲染树。
- 合成DOM树和CSS渲染树:将DOM树和CSS渲染树结合起来生成最终的页面。
此外,JavaScript的执行是单线程的,而浏览器本身是多线程的。当页面中包含img、link、script等标签时,浏览器会启动新的下载线程来并发处理这些资源。然而,同时下载过多的图片会导致资源的拥堵,就像在高速公路上发生堵车一样。那么问题来了:是否有必要同时并发下载那么多图片?
性能优化
为了提高页面的性能,我们通常采取以下几种策略:
- 首屏图片加载:优先加载用户首次看到的视窗中的图片,以便页面尽快显示出来。
- 滚动懒加载:当用户滚动到图片所在位置时才加载图片,从而减少初始加载的资源占用。
- 尽快显示页面:前端开发的基本任务是尽可能快地显示页面,让用户感觉页面加载速度更快。
具体实现
实现图片懒加载的具体步骤如下:
手动控制图片加载
通常情况下,直接在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)
总结
总的来说,图片懒加载不仅能够显著提高页面性能,还能让我们更深入地理解浏览器的工作机制和前端性能优化的策略。在实际项目中,结合具体业务场景,合理地实现和优化懒加载,可以为用户带来更好的浏览体验。