懒加载的实现原理
图片的加载是由src引起的,当对src赋值时,浏览器就会请求图片资源。根据这个原理,我们使用HTML5 的data-xxx属性来储存图片的路径,在需要加载图片的时候,将data-xxx中图片的路径赋值给src,这样就实现了图片的按需加载,即懒加载。
1.通过getBoundingClientRect()和window.innerHeight
流程:
- 获得图片列表imgList = [...document.querySelectorAll('img')]
- 创建懒加载自执行函数,创建空数组,把加载过的图片下标加入数组
- 监听滚动事件
- 遍历图片,获得图片相对于视口的位置。getBoundingClientRect().top
- 图片位置小于window.innerHeight,则更改src,getAttribute(‘’)
- 设置透明度
- 当加载完所有图片,移除监听事件document.removeEventListener('scroll', imgLazyLoad)
<!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> <body> <style> .box{ background-color: #DDD; width:200px; height:100px; } .box img{ opacity: 0; transition: opacity 2s; } </style> <div class="box"> <img src='' data-src="./1.jpg"/ style="width:200px; height:100px;"> </div><br><br><br><br><br><br><br> <div class="box"> <img src='' data-src="./1.jpg"/ style="width:200px; height:100px;"> </div><br><br><br><br><br><br><br> <div class="box"> <img src='' data-src="./1.jpg"/ style="width:200px; height:100px;"> </div><br><br><br><br><br><br><br> <div class="box"> <img src='' data-src="./1.jpg"/ style="width:200px; height:100px;"> </div><br><br><br><br><br><br><br> <div class="box"> <img src='' data-src="./1.jpg"/ style="width:200px; height:100px;"> </div><br><br><br><br><br><br><br> <script type="text/javascript"> let imgList = [...document.querySelectorAll('img')] let length = imgList.length const imgLazyLoad = (function() { let count = 0 return function() { let deleteIndexList = [] //遍历图片 imgList.forEach((img, index) => { let rect = img.getBoundingClientRect() //出现在可视窗口时,开始加载 if (rect.top < window.innerHeight) { //更改地址 img.src=img.getAttribute('data-src') //设置透明度 img.onload=()=>{ img.style.opacity=1 } deleteIndexList.push(index) count++ //加载完所有图片之后,移除滚动条的监听事件 if (count === length) { document.removeEventListener('scroll', imgLazyLoad) } } }) //加载过的图片从列表中移除 imgList = imgList.filter((img, index) => !deleteIndexList.includes(index)) } })() //监听滚动事件 document.addEventListener('scroll', imgLazyLoad) </script> </body> </html>
2,通过IntersectionObserver接口 (交叉观察器)
创建观察器:new IntersectionObserver(callback, option);
callback一般会触发两次。一次是目标元素刚刚进入视口(开始可见),另一次是完全离开视口(开始不可见)。
callback函数的参数(entries)是一个数组,被观察的对象。
用到的两个api:
IntersectionObserverEntry.target (en-US) 只读,获得可视区域内的元素
IntersectionObserverEntry.isIntersecting (en-US) 只读,返回一个布尔值, 如果目标元素与交叉区域观察者对象的根相交,则返回 true .(是否在可视区域内)
添加观察:observer()
取消观察:unobserver()
流程:
- 获取所有图片
- 创建监听器,并指定回调函数IntersectionObserver(dd)
- 给每个img都添加监视 observe.observe(img)
- 遍历回调函数中的参数(数组:被观察的对象),判断其是否在可视区域内isIntersecting,如果在,则获取该元素target
- 更改src,改变透明度,取消观察observe.unobserve(img)
<!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">
<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5"/>
<title>Document</title>
<style>
img{
opacity: 0;
transition: opacity 2s;
}
</style>
</head>
<body>
<img src="" data-src="1.jpg" style="width:200px;height:200px;">
<br/><br/><br/><br/><br/>
<img src="" data-src="1.jpg" style="width:200px;height:200px;">
<br/><br/><br/><br/><br/>
<img src="" data-src="1.jpg" style="width:200px;height:200px;">
<br/><br/><br/><br/><br/>
<img src="" data-src="1.jpg" style="width:200px;height:200px;">
<br/><br/><br/><br/><br/>
<img src="" data-src="1.jpg" style="width:200px;height:200px;">
<br/><br/><br/><br/><br/>
<img src="" data-src="1.jpg" style="width:200px;height:200px;">
<br/><br/><br/><br/><br/>
<img src="" data-src="1.jpg" style="width:200px;height:200px;">
<br/><br/><br/><br/><br/>
<script type="text/javascript">
let list=document.querySelectorAll('img')
const dd=arr=>{
arr.forEach(item=>{
if(item.isIntersecting){
let img=item.target
img.src=img.getAttribute('data-src')
img.onload=()=>{
img.style.opacity=1
}
observer.unobserve(img)
}
})
}
let observer=new IntersectionObserver(dd)
list.forEach(img=>{
observer.observe(img)
})
</script>
</body>
</html>