懒加载的实现原理
图片的加载是由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.lengthconst imgLazyLoad = (function() {let count = 0return 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接口(交叉观察器)
创建观察器:newIntersectionObserver(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.targetimg.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>