前端工程师在做页面优化的时候,如果页面中是类似图片列表的结构,会考虑使用懒加载(Lazy-Load)技术来优化页面的加载速度,今天就带大家来探究一下懒加载的原理。
首先我们实现页面布局,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.out{
position: relative;
}
.inner{
width: 300px;
list-style: none;
margin: 0 auto;
}
li{
width:300px;
height: 300px;
margin-top: 10px;
overflow: hidden;
}
img{background: url("./image/t.gif");width: 100%;height: 100%;background-size: cover}
</style>
</head>
<body>
<div class="out">
<ul class="inner">
<li><img datasrc="./image/1.jpg" alt=""></li>
<li><img datasrc="./image/2.jpg" alt=""></li>
<li><img datasrc="./image/3.jpg" alt=""></li>
<li><img datasrc="./image/4.jpg" alt=""></li>
<li><img datasrc="./image/5.jpg" alt=""></li>
<li><img datasrc="./image/5.jpg" alt=""></li>
<li><img datasrc="./image/6.jpg" alt=""></li>
<li><img datasrc="./image/7.jpg" alt=""></li>
<li><img datasrc="./image/8.jpg" alt=""></li>
<li><img datasrc="./image/9.jpg" alt=""></li>
<li><img datasrc="./image/10.jpg" alt=""></li>
<li><img datasrc="./image/11.jpg" alt=""></li>
<li><img datasrc="./image/12.jpg" alt=""></li>
<li><img datasrc="./image/13.jpg" alt=""></li>
<li><img datasrc="./image/14.jpg" alt=""></li>
<li><img datasrc="./image/15.jpg" alt=""></li>
<li><img datasrc="./image/15.jpg" alt=""></li>
<li><img datasrc="./image/16.jpg" alt=""></li>
<li><img datasrc="./image/17.jpg" alt=""></li>
<li><img datasrc="./image/18.jpg" alt=""></li>
<li><img datasrc="./image/19.jpg" alt=""></li>
<li><img datasrc="./image/20.jpg" alt=""></li>
<li><img datasrc="./image/21.jpg" alt=""></li>
<li><img datasrc="./image/22.jpg" alt=""></li>
<li><img datasrc="./image/23.jpg" alt=""></li>
</ul>
</div>
<script>
</script>
</body>
</html>
观察上面代码,我们发现img的src属性不存在,反而存在一个datasrc属性,datasrc属性中存储的反而是图片的真是地址。
这里我们用了一个img的背景图设置图片的默认显示图片,页面显示如下:
接下来就是实现图片懒加载的功能了,如何做呢?可以看到默认情况下图片显示的是gif图,用户拖动滚动框,当图片出现在浏览器的可视区域后,我们将图片的src值设置为datasrc,这样的话图片就实现了懒加载功能。
梳理上面的功能,我们发现:
1、我们需要监听网页的scroll事件
2、我们需要判断图片是否出现在浏览器的可视区域。
第一步可以轻松实现,但是第二步,如何判断图片出现在了可视区域呢?
首先我们可以用window.innerHeight或者document.documentElement.clientHeight来获取浏览器可视区域的高度,screenheight。
然后我们可以通过图片的getBoundingClientRect() 方法来获取返回元素的大小及其相对于视口的位置。对此 MDN 给出了非常清晰的解释:
该方法的返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合, 即:是与该元素相关的 CSS 边框集合 。 DOMRect 对象包含了一组用于描述边框的只读属性——left、top、right 和 bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。 mdn
其中需要引起我们注意的就是 left、top、right 和 bottom,它们对应到元素上是这样的:
我们只需要获取可视区域的高度screen与img.getBoundingClientRect().top的差值是否大于等于0,就可以判断出图片是否出现在了可视区域内。
js脚本代码如下:
<script>
var screenHeight = window.innerHeight||document.documentElement.clientHeight;
var count = 0;
var img = document.querySelectorAll('.inner img');
function show(){
for(var i=count;i<img.length;i++){
console.log(i);
var top = img[i].getBoundingClientRect().top;
if(screenHeight-top >= 0){
img[i].src = img[i].getAttribute('datasrc')
count++;
}
}
}
show();
document.onscroll = show
</script>
仔细观察代码逻辑,每次触发滚动事件,都会计算可视区域顶部与每张图片距离可视区域顶部的差值,如果大于0;说明图片出现在可视区域,将图片的src设置为图片的真实地址,这里需要注意的是页面初始加载进来时是不会滚动的,所以我们要主动执行一下show方法。
这里需要注意的是,我们设置了一个count变量,每次图片显示,将count递增,再次检测图片时从count开始检测,防止重复检测。
到此为止我们完成了图片懒加载额功能,下面是优化的代码,上面的scroll事件触发频率太高了,上篇文章,我们介绍了防抖,我们将其用在这个案例上,优化代码如下:
<script>
var screenHeight = window.innerHeight||document.documentElement.clientHeight;
var count = 0;
var img = document.querySelectorAll('.inner img');
function show(){
for(var i=count;i<img.length;i++){
console.log(i);
var top = img[i].getBoundingClientRect().top;
if(screenHeight-top >= 0){
img[i].src = img[i].getAttribute('datasrc')
count++;
}
}
}
// 扩展防抖方法debounce
function debounce(cb){
var timer = null;
return function(e){
console.log(111)
var context = this;
var event = e;
if(timer){
clearTimeout(timer);
timer = setTimeout(function(){
cb.call(context,event)
},600)
}else{
timer = setTimeout(function(){
cb.call(context,event)
},600)
}
}
}
document.onscroll = debounce(show);
show();
</script>