优化首屏体验
Lazy-Load 初探
掘金首页采用了懒加载策略。当我们的页面并未滚动至包含图片的 div 元素所在的位置时,它的样式是这样的:
js
<div data-v-b2db8566=""
data-v-009ea7bb=""
data-v-6b46a625=""
data-src="https://user-gold-cdn.xitu.io/2018/9/27/16619f449ee24252?imageView2/1/w/120/h/120/q/85/format/webp/interlace/1"
class="lazy thumb thumb"
style="background-image: none; background-size: cover;">
</div>
- 我们注意到
style
内联样式中,背景图片设置为了none
。也就是说这个div
是没有内容的,它只起到一个占位的作用。 - 一旦我们通过滚动使得这个
div
出现在了可见范围内,那么div
元素的内容就会发生变化,呈现如下的内容:
js
style="background-image: url("https://user-gold-cdn.xitu.io/2018/9/27/16619f449ee24252?imageView2/1/w/120/h/120/q/85/format/webp/interlace/1"); background-size: cover;"
一起写一个 Lazy-Load
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta >
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Lazy-Load</title>
<style>
.img {
width: 200px;
height:200px;
background-color: gray;
}
.pic {
// 必要的img样式
}
</style>
</head>
<body>
<div class="container">
<div class="img">
// 注意我们并没有为它引入真实的src
<img class="pic" alt="加载中" data-src="./images/1.png">
</div>
<div class="img">
<img class="pic" alt="加载中" data-src="./images/2.png">
</div>
<div class="img">
<img class="pic" alt="加载中" data-src="./images/3.png">
</div>
<div class="img">
<img class="pic" alt="加载中" data-src="./images/4.png">
</div>
<div class="img">
<img class="pic" alt="加载中" data-src="./images/5.png">
</div>
<div class="img">
<img class="pic" alt="加载中" data-src="./images/6.png">
</div>
<div class="img">
<img class="pic" alt="加载中" data-src="./images/7.png">
</div>
<div class="img">
<img class="pic" alt="加载中" data-src="./images/8.png">
</div>
<div class="img">
<img class="pic" alt="加载中" data-src="./images/9.png">
</div>
<div class="img">
<img class="pic" alt="加载中" data-src="./images/10.png">
</div>
</div>
</body>
</html>
- 在懒加载的实现中,有两个关键的数值:一个是当前可视区域的高度 ,另一个是元素距离可视区域顶部的高度。
- 当前可视区域的高度 , 在和现代浏览器及 IE9 以上的浏览器中,可以用
window.innerHeight
属性获取。在低版本 IE 的标准模式中,可以用document.documentElement.clientHeight
获取,这里我们兼容两种情况:
js
const viewHeight = window.innerHeight || document.documentElement.clientHeight
而元素距离可视区域顶部的高度 ,我们这里选用 getBoundingClientRect()
方法来获取返回元素的大小及其相对于视口的位置。对此 MDN 给出了非常清晰的解释:
返回的
DOMRect
对象包含了一组用于描述边框的只读属性---------left
、top
、right
和bottom
,单位为像素。除了width
和height
外的属性都是相对于视口的左上角位置而言的。
Lazy-Load 方法的实现:
html
<script>
// 获取所有的图片标签
const imgs = document.getElementsByTagName('img')
// 获取可视区域的高度
const viewHeight = window.innerHeight || document.documentElement.clientHeight
// num用于统计当前显示到了哪一张图片,避免每次都从第一张图片开始检查是否露出
let num = 0
function lazyload(){
for(let i=num; i<imgs.length; i++) {
// 用可视区域高度减去元素顶部距离可视区域顶部的高度
let distance = viewHeight - imgs[i].getBoundingClientRect().top
// 如果可视区域高度大于等于元素顶部距离可视区域顶部的高度,说明元素露出
if(distance >= 0 ){
// 给元素写入真实的src,展示图片
imgs[i].src = imgs[i].getAttribute('data-src')
// 前i张图片已经加载完毕,下次从第i+1张开始检查是否露出
num = i + 1
}
}
}
// 监听Scroll事件
window.addEventListener('scroll', lazyload, false);
</script>