JS图片懒加载(详解注释+功能解析)
一、前言
懒加载原理: 图片进入可视区域之后再去请求图片资源。
实现原理:
1.使用img标签,scr属性初始为空
2.写一个自定义属性字段,该属性的值写成图片地址
3.当图片在可视区域的范围内的时候,将自定义属性的值作为src的值
图片是在img标签有src属性才去加载的。
- 懒加载的原理就是在图片进入可视化区域之后,动态的去设置img标签中的src属性。如果在可视区域之外的图片的img中的src属性已被提前设置,那么就不是懒加载了,而是所有图片都会被加载。
- 在图片进入可视化区域之前,img标签上的src属性并没有被设置。在img标签上有一个data-url属性。该属性的值存放着图片的真实请求地址,但是由于src属性上并没有值,所以图片并不会被加载。我们的js可以监听scroll事件,在计算到图片进入可视区域之后。就拿到img标签上的data-url属性的值,把它设置到src属性上,这就是懒加载的一个原理。
图片懒加载的优势:
- 对于电商等图片很多,页面很长的业务场景适用
- 减少无效资源的加载:比如我们的页面有100张图片,但是用户往下滑动看的时候只看了十张图片。如果我们把这100张图片全部都加载完成,页面上会有很多的浪费。所以就可以使用懒加载,图片进入可视区域之后再去加载。
- 并发加载的资源过多会阻塞js的加载,影响网站的正常使用。因为浏览器会限制在一个域名下并发请求的数量。如果前边图片加载数量过多,要发送http请求,就会影响到后边js的并发加载,影响到页面中js逻辑的使用(JS文件一般放在页面底部)。使用图片懒加载可以避免这个问题。
二、代码注释详解
<!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>
</head>
<style>
.box {
width: 400px;
margin: 0 auto;
}
.box img {
display: block;
width: 100%;
height: 200px;
}
</style>
<body>
<div class="box">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/夕阳.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/沙滩.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/湖泊.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/雪山.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/夕阳.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/沙滩.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/湖泊.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/雪山.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/夕阳.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/沙滩.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/湖泊.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/雪山.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/夕阳.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/沙滩.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/湖泊.jpg">
<img src="./imgs/加载中.jpg" alt="" class="lazyload-img" data-src="./imgs/雪山.jpg">
</div>
<script>
// 获取根元素节点
let viewport = document.documentElement;
// 把DOM节点数组转为真正的数组,即伪数组转数组
// let imgArr = [].slice.call(document.querySelectorAll('.lazyload-img'));
let imgArr = Array.from(document.querySelectorAll('.lazyload-img'))
// 该函数用来判断某一个元素是否在可视区域
function isVisible(element) {
// 获取当前元素节点的大小、位置等信息
let rect = element.getBoundingClientRect();
// 用户不管是从上向下、从下向上、从左向右、从右向左滑动,都可以判断当前元素是否在可视区域
return rect.top < viewport.clientHeight && rect.bottom > 0 && rect.left < viewport.clientWidth && rect.right > 0;
}
//防抖处理
let timer = null;
// 该函数动态设置图片的src属性,动态加载图片
function lazyloadImg() {
for (let i = 0; i < imgArr.length; i++) {
let img = imgArr[i];
// 如果元素在可视区域内
if (isVisible(img)) {
// 则把data-src属性赋值给data-src
img.src = img.getAttribute('data-src');
// 当前元素从未加载数组中移除
imgArr.splice(i, 1);
// 后一下标前移至当前下标,自减再循环
i--;
}
}
// 可视区域内加载完成后,防抖限制解除
timer = null;
}
// 一开始先执行一次,把当前时间在可视区域的图片加载出来
lazyloadImg();
// 监听页面滚动
document.addEventListener('scroll', function () {
// 如果已触发滚动期间再触发
console.log(timer);
if (timer) {
// 则清除现有执行
return clearTimeout(timer);
}
// 重新赋值
timer = setTimeout(() => {
// 页面滚动的时候,不断有新的图片进入可视区域,此时再调用lazyloadImg函数
lazyloadImg();
}, 100);
})
console.log(timer);
</script>
</body>
</html>
三、功能解析
1、document.documentElement
document.documentElement
属性返回当前文档的根元素节点。HTML网页的该属性一般是<html>
节点。
document.documentElement的clientHeight
属性,返回当前视口的高度(即浏览器窗口的高度,不包括滚动条)。
document.documentElement的clientWidth
属性,返回当前视口的宽度(即浏览器窗口的宽度,不包括滚动条)。
另外,window.innerHeight
和 window.innerWidth
属性,也会返回网页在当前窗口中可见部分的高度和宽度,即“视口”(viewport)的大小(单位像素)。但是这两个属性值包括滚动条的高度和宽度。
2、Array.from() 或 [].slice.call()
- 即伪数组转数组
3、getBoundingClientRect()
getBoundingClientRect
方法(所有的元素结点上都有这个方法)返回一个对象,提供当前元素节点的大小、位置等信息,基本上就是 CSS 盒模型的所有信息。
let rect = obj.getBoundingClientRect();
getBoundingClientRect方法返回的rect对象,具有以下属性:
- x:元素左上角相对于视口的横坐标
- y:元素左上角相对于视口的纵坐标
- height:元素高度
- width:元素宽度
- left:元素左上角相对于视口的横坐标,与x属性相等
- right:元素右边界相对于视口的横坐标(等于x + width)
- top:元素顶部相对于视口的纵坐标,与y属性相等
- bottom:元素底部相对于视口的纵坐标(等于y + height)
由于元素相对于视口(viewport)的位置,会随着页面滚动变化,因此表示位置的四个属性值,都不是固定不变的。
注意,getBoundingClientRect方法的所有属性,都把边框(border属性)算作元素的一部分。也就是说,都是从边框外缘的各个点来计算。因此,width和height包括了元素本身 + padding + border
。
转载自:https://juejin.cn/post/7238479969180074045