懒加载冰墩墩和雪绒容
一、前言
不得不说,最近冰墩墩是一"墩"难求,作为我们的冬奥顶流,冰墩墩无疑是当下最大的热点,正好最近我也在学习关于前端优化的板块,今天我们就来一起看一下如何懒加载一个冰墩墩;
二、背景
前端优化是一个非常重要的课题,而今天我们主要是来展示一下如何通过懒加载来减少首屏的压力;
众所周知,首屏加载资源的过程中,比如电商,那么多图片,那么多信息,都需要在用户打开时一下子展示出来;但实际上,用户往往看到的部分,并不是全部的内容,而是局部的内容,那是不是可以只展示用户视觉能够感知到的内容会更好一点呢,是的,这样的话,就可以减少首屏加载的压力!当用户触发诸如滚动的操作的时候,再展示用户想要看到的内容;实际上,这也是现如今大部分电商网站,尤其是手机端都在做的事情;
三、实践
我们今天使用一张冰墩墩和雪绒容的合照来作为目标图片加载;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#container {
width: 100vw;
height: 100vh;
}
.img {
width: 300px;
height: 200px;
border-radius: 8px;
background: #eee;
margin: 10px auto;
}
img {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="container">
<div class="img">
<img data-src="./imgs/bingdundun.jpeg">
</div>
<div class="img">
<img data-src="./imgs/bingdundun.jpeg">
</div>
<div class="img">
<img data-src="./imgs/bingdundun.jpeg">
</div>
<div class="img">
<img data-src="./imgs/bingdundun.jpeg">
</div>
<div class="img">
<img data-src="./imgs/bingdundun.jpeg">
</div>
<div class="img">
<img data-src="./imgs/bingdundun.jpeg">
</div>
<div class="img">
<img data-src="./imgs/bingdundun.jpeg">
</div>
<div class="img">
<img data-src="./imgs/bingdundun.jpeg">
</div>
</div>
</body>
</html>
以上是html的部分;使用一个阴影图片进行展位;将实际的资源路径挂在到dom上;这里的css有一个小技巧,因为如何img标签没有src属性,会有一个非border的边框;如下图所示;
所以我们加一个样式
img:not([src]) {
opacity: 0;
}
对于没有src属性的,我们统一使其透明度变为0,之后使用js动态添加src,那么该样式就不生效了,图片就加载出来了;我们先看一下效果图;
接下来是js的部分;是这样设想的;对于处于视口的内容,我们让其加载,对于不处于视口的不让加载;
let imgs = document.getElementsByTagName("img");
function addBackground(dom) {
dom.src = dom.dataset.src;
}
function checkAndAddBackground() {
let viewHeight = window.innerHeight;
Array.from(imgs).forEach(img => {
if (!img.src) {
let top = img.getBoundingClientRect().top;
if (top <= viewHeight) {
addBackground(img)
}
}
});
}
先定义两个函数;一个用于将指定的img添加上src,另一个是检查每一个img,如果已加载,忽略,如果未加载,那么就判断是否在视口内,只有在视口内的才进行加载;否则忽略;
看是否在视口,使用的是一个getBoundingClientRect的api;它的使用形如下图;
function main() {
checkAndAddBackground();
let container = document.createElement("container");
window.addEventListener("scroll", checkAndAddBackground)
}
main() // 调用主函数;
上面的代码添加上之后,其实就可以完成懒加载的效果了,但是特别不好;因为checkAndBackground触发的频率太高;我们需要使用防抖函数进行一个优化;
function debounce(func, delay) {
let timer = null;
return function (args) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(this, args)
}, delay);
}
}
function main() {
checkAndAddBackground();
let container = document.createElement("container");
let listenScroll = debounce(checkAndAddBackground, 500);
window.addEventListener("scroll", listenScroll)
}
main();
通过上面的优化我们现在来看一下效果;