1.什么是懒加载?
懒加载也就是延迟加载。
当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次,俗称占位图),
只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。这就是图片懒加载。
2.为什么要使用懒加载?
很多页面,内容很丰富,页面很长,图片较多。比如说各种商城页面。这些页面图片数量多,而且比较大,少说百来K,多则上兆。
要是页面载入就一次性加载完毕。估计大家都会等到黄花变成黄花菜了。
3.懒加载的原理是什么?
页面中的img元素,如果没有src属性,浏览器就不会发出请求去下载图片,
只有通过javascript设置了图片路径,浏览器才会发送请求。
懒加载的原理就是先在页面中把所有的图片统一使用一张占位图进行占位,
把真正的路径存在元素的“data-url”(这个名字起个自己认识好记的就行)属性里,要用的时候就取出来,再设置;
4.懒加载的实现步骤?
1)首先,不要将图片地址放到src属性中,而是放到其它属性(data-original)中。
2)页面加载完成后,根据scrollTop判断图片是否在用户的视野内,如果在,则将data-original属性中的值取出存放到src属性中。
3)在滚动事件中重复判断图片是否进入视野,如果进入,则将data-original属性中的值取出存放到src属性中。
5.懒加载的优点是什么?
页面加载速度快、可以减轻服务器的压力、节约了流量,用户体验好
6:懒加载代码实现
方式一:
元素距顶部的高度 - 页面被卷去的高度 <= 浏览器可视区的高度)
来判断是否符合我们想要的条件.需要实时监听页面滚动时 图片的高度变化
<!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>
* {
padding: 0;
margin: 0;
list-style: none;
}
img {
width: 400px;
height: 300px;
}
</style>
<script>
window.onload = function () {
var imgs = document.querySelectorAll("img");
// 初始化执行
lazyLoad(imgs);
// 滚动执行
window.addEventListener("scroll", function () {
lazyLoad(imgs);
});
function lazyLoad(imgs) {
for (let i = 0; i < imgs.length; i++) {
var imgoffsetT = imgs[i].offsetTop; // 图片的距顶部的高度
var wheight = window.innerHeight; // 浏览器可视区的高度
var scrollT = document.documentElement.scrollTop; // 页面被卷去的高度
if (imgoffsetT - scrollT <= wheight) {
// 判断图片是否将要出现
imgs[i].src = imgs[i].dataset.src; // 出现后将自定义地址转为真实地址
}
}
}
};
/*
obj.getAttribute("属性名")
通过元素节点的属性名称获取属性的值。
使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,
dataset 获取自定义属性值的使用
*/
</script>
</head>
<body>
<ul>
<li>
<img data-src="./img/img1.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img2.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img3.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img4.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img5.png" src="./img/loading.gif" alt="" />
</li>
</ul>
</body>
</html>
方式二 getBoundingClientRect()
<!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>
* {
padding: 0;
margin: 0;
list-style: none;
}
img {
width: 400px;
height: 300px;
}
</style>
<script>
window.onload = function () {
var imgs = document.querySelectorAll("img");
// 初始调动一次
lazyLoad();
window.addEventListener("scroll", throttle(lazyLoad, 1000), false);
//函数1:封装判定图片是否在可视区
function isInVisibleArea(imgOne) {
const info = imgOne.getBoundingClientRect();
// 获取页面可视区的高度,宽度
let windowH = window.innerHeight;
let windowW = window.innerWidth;
// 限定参数在可视区内
let res = info.bottom > 0 && info.top < windowH && info.right > 0 && info.left < windowW;
return res;
}
//函数2: 封装滚动时重新加载函数
function lazyLoad() {
for (let i = 0; i < imgs.length; i++) {
const imgOne = imgs[i];
// 判定是否在可视区内
if (isInVisibleArea(imgOne)) {
// 替换src方法一:
// imgOne.src = imgOne.getAttribute("data-src");
// 替换src方法二:
imgOne.src = imgOne.dataset.src;
// imgs.splice(i,1)
// i--;
}
console.log("我滚了"); //所以要做节流操作
}
}
//函数3:节流函数
/*
参数1: 函数
参数2:执行时间
*/
function throttle(fn, time = 250) {
let lastTime = null;
return function (...args) {
const now = Date.now(); //当前时间
if (now - lastTime >= time) {
fn();//帮助执行函数,改变上下文
lastTime = now;
}
};
}
};
/*
getBoundingClientRect()
——获取元素位置,这个方法没有参数
——用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。
——是DOM元素到浏览器可视范围的距离(不包含文档卷起的部分)。
该函数返回一个Object对象,该对象有6个属性:top,lef,right,bottom,width,height;
*/
</script>
</head>
<body>
<ul>
<li>
<img data-src="./img/img1.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img2.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img3.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img4.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img5.png" src="./img/loading.gif" alt="" />
</li>
</ul>
</body>
</html>
方式三:IntersectionObserver(callback)
<!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>
* {
padding: 0;
margin: 0;
list-style: none;
}
img {
width: 400px;
height: 300px;
}
</style>
</head>
<body>
<ul id="view">
<li>
<img data-src="./img/img1.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img2.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img3.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img4.gif" src="./img/loading.gif" alt="" />
</li>
<li>
<img data-src="./img/img5.png" src="./img/loading.gif" alt="" />
</li>
</ul>
<script>
const imgs = document.querySelectorAll("img");
const callback = (res) => {
//res 是观察的元素数组 info 每个被观察的图片信息
res.forEach((info) => {
// isIntersecting 目标是否被观察到,返回布尔值
if (info.isIntersecting) {
// img 就是当前的图片标签
const img = info.target;
img.src = img.getAttribute("data-src");
// 真实地址替换后 取消对它的观察
obs.unobserve(img);
console.log("触发");
}
});
};
const obs = new IntersectionObserver(callback);// 实例化 IntersectionObserver
// 遍历imgs所有的图片,然后给每个图片添加观察实例
imgs.forEach((img) => {
// observe : 被调用的IntersectionObserver实例。给每个图片添加观察实例
obs.observe(img);
});
/* IntersectionObserver(callback)
callback回调触发两次,看见了出发,看不见也触发
*/
</script>
</body>
</html>