一、懒加载的理解
-
懒加载:
1)懒加载其实就是延迟加载,是一种对网页性能优化的方式,比如当访问一个页面的时候,优先显示可视区域的图片而不一次性加载所有图片,当需要显示的时候再发送图片请求,避免打开网页时加载过多资源
2)在图片非常多的应用场景,为了提高页面加载速度,改善用户体验,我们对未出现在视野范围内的图片先不进行加载,等到出现在视野范围才去加载
3)懒加载(LazyLoad)是前端优化的一种有效方式,极大的提升用户体验 -
懒加载的运用场景:
1)当页面中需要一次性载入很多图片的时候,往往都是需要用懒加载的
2)如果一次ajax请求数量过多的图片,把它们全部加载出来,会显示的很慢,对于用户的显示体验造成很大的影响 -
懒加载的原理:
先把img的src指向空或者一个小图片,图片真实的地址存储在img一个自定义的属性里,< img src=”” data-src=”http://real.com/real.jpg” />
,等到此图片出现在视野范围内了,获取img元素,把data-src里的值赋给src -
判断元素是否在可视区域
1)通过document.documentElement.clientHeight
获取屏幕可视窗口高度
通过element.offsetTop
获取元素相对于文档顶部的距离
通过document.documentElement.scrollTop
获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离
判断element.offsetTop - document.documentElement.scrollTop < document.documentElement.clientHeight
是否成立,如果成立,元素就在可视区域内
2)通过getBoundingClientRect()方法来获取元素的大小以及位置,这个方法返回一个名为ClientRect的DOMRect对象,包含了top、right、botton、left、width、height这些值
当bound.top<=clientHeight
的时候,图片是在可视区域的
封装代码如下:
function isInSight(el) {
const bound = el.getBoundingClientRect();
const clientHeight = window.innerHeight;
//如果只考虑向下滚动加载
//const clientWidth = window.innerWeight;
return bound.top <= clientHeight + 100;
}
3)IntersectionObserver可以自动观察元素是否在视口内
可以用到intersectionRatio来判断是否在可视区域内,当intersectionRatio > 0 && intersectionRatio <= 1
即在可视区域内
封装代码如下:
var io = new IntersectionObserver(callback, option);
// 开始观察
io.observe(document.getElementById('example'));
// 停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect();
- 加载图片
1)页面打开时需要对所有图片进行检查,是否在可视区域内,如果是就加载
2)封装代码如下:
function checkImgs() {
const imgs = document.querySelectorAll('.my-photo');
Array.from(imgs).forEach(el => {
if (isInSight(el)) {
loadImg(el);
}
})
}
function loadImg(el) {
if (!el.src) {
const source = el.dataset.src;
el.src = source;
}
说明:优化的地方是设一个标识符标识已经加载图片的index,当滚动条滚动时就不需要遍历所有的图片,只需要遍历未加载的图片即可
- 函数节流优化
1)在类似于滚动条滚动等频繁的DOM操作时,可以进行函数节流和函数去抖
2)函数节流:让一个函数不要执行的太频繁,减少一些过快的调用来节流
3)基本步骤:
获取第一次触发事件的时间戳
获取第二次触发事件的时间戳
时间差如果大于某个阈值就执行事件,然后重置第一个时间
4)封装代码如下:
function throttle(fn, mustRun = 500) {
const timer = null;
let previous = null;
return function() {
const now = new Date();
const context = this;
const args = arguments;
if (!previous){
previous = now;
}
const remaining = now - previous;
if (mustRun && remaining >= mustRun) {
fn.apply(context, args);
previous = now;
}
}
}
说明:mustRun就是调用函数的时间间隔,无论多么频繁的调用fn,只有remaining>=mustRun时fn才能被执行
二、懒加载的实现
- 简单的懒加载实现
1)html 部分:
<!--data-* 全局属性:构成一类名称为自定义数据属性的属性,可以通过HTMLElement.dataset来访问-->
<img src="" data-src="./images/1.jpg" >
<img src="" data-src="./images/2.jpg" >
<img src="" data-src="./images/3.jpg" >
<img src="" data-src="./images/4.jpg" >
<img src="" data-src="./images/5.jpg" >
<img src="" data-src="./images/6.jpg" >
<img src="" data-src="./images/7.jpg" >
<img src="" data-src="./images/8.jpg" >
2)js部分:
window.onload = function(){
// 获取元素
var img = document.querySelectorAll("img");
var len = img.length;
// 存储图片的加载位置
var n = 0;
// 获取图片的可视区域
var height = document.documentElement.clientHeight;
var top = document.body.scrollTop || document.documentElement.scrollTop;
for(var i=n;i<len;i++){
if(img[i].offsetTop< height + top){
if(img[i].getAttribute("src")==""){
img[i].src = img[i].getAttribute("data-src");
}
n = i + 1;
console.log("第"+n+"张图片"+",n="+n);
}
}
};
3)在当打开页面的时候
console 控制台输出:
network 网络输出:
4)在打开页面滚动的时候
console 控制台输出:
network 网络输出:
5)通过在打开页面的时候,网页中的图片是没有全部加载出来的,从network中可以看出只加载出了两张图片资源。在打开页面进行滚动以后,后面的图片资源才慢慢加载出来,在network中看出,但是也只是展示出了五张图片的资源,展示出了我们的可视区域,剩下的图片也是没有加载出来,这样恰恰就可以实现了图片的懒加载,保证一次请求不会请求所有的资源,在出现可视区域后才会加载出来,提高了前端的性能优化
- 懒加载的封装函数
1)代码如下:
function checkImgs() {
const imgs = Array.from(document.querySelectorAll(".my-photo"));
imgs.forEach(item => io.observe(item));
}
function loadImg(el) {
if (!el.src) {
const source = el.dataset.src;
el.src = source;
}
}
const io = new IntersectionObserver(ioes => {
ioes.forEach(ioe => {
const el = ioe.target;
const intersectionRatio = ioe.intersectionRatio;
if (intersectionRatio > 0 && intersectionRatio <= 1) {
loadImg(el);
}
el.onload = el.onerror = () => io.unobserve(el);
});
});