实现图片懒加载
懒加载是一种网页性能优化方式,提升用户体验,比如懒加载图片,进入页面时,我们只请求可视区域的图片资源
总结:
全部加载会影响用户体验
浪费用户的流量,有些用户不想全部看完,全部加载会耗费大量流量
实现方式:
html实现
最简单的实现方式给img标签加上 loading=”lazy”
1 <img src="./example.jpg" loading="lazy" >
js实现原理
通过js监听页面的滚动
使用js实现的原理主要是判断当前图片是否到了可视区域:
拿到所有图片的dom
遍历每个图片判断当前图片是否到达了可视区域范围
如果到了就设置图片的src属性
绑定window的scroll事件,对其进行事件监听
在页面初始化时,img图片的src放在data-src属性上,当匀速处于可视区范围,就把data-src赋值给src属性,完成图片加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <html lang ="en" > <head > <meta charset ="UTF-8" /> <title > Lazyload</title > <style > img { display : block; margin-bottom : 50px ; height : 200px ; width : 400px ; } </style > </head > <body > <img src ="./img/default.png" data-src ="./img/1.jpg" /> <img src ="./img/default.png" data-src ="./img/2.jpg" /> <img src ="./img/default.png" data-src ="./img/3.jpg" /> <img src ="./img/default.png" data-src ="./img/4.jpg" /> <img src ="./img/default.png" data-src ="./img/5.jpg" /> <img src ="./img/default.png" data-src ="./img/6.jpg" /> <img src ="./img/default.png" data-src ="./img/7.jpg" /> <img src ="./img/default.png" data-src ="./img/8.jpg" /> <img src ="./img/default.png" data-src ="./img/9.jpg" /> <img src ="./img/default.png" data-src ="./img/10.jpg" /> </body > </html >
先获取所有图片的dom,通过document.body.clientHeight获取可视区高度,在使用element.getBoundingClientRect()直接得到元素相对浏览器的top值 ,遍历每个图片判断图片是否到达了可视区域
1 2 3 4 5 6 7 8 9 10 11 12 13 function lazyLoad ( ) { let viewHeight=document .body.clientHeight; let imgs=document .querySelectorAll("img[data-src]" ) imgs.forEach(item => { if (item.data-src=='' )return ; let rect=item.getBoundingClientRect(); if (rect.top<viewHeight&&rect.bottom>=0 ){ item.src=item.data-src item.removeAttribute('data-src' ) } }) }
这样存在性能问题,因为scroll事件会在很短事件内触发多次,严重影响页面性能,为了提高网页性能,我们需要一个节流函数来控制函数的多次触发,在一段时间内只执行一次回调
1 2 3 4 5 6 7 8 9 10 11 12 13 function throttle (fn,delay ) { let timer=null ; return function (fn,...args ) { const context=this ; if (!temer){ timer=setTimeout (()=> { fn.apply(context,args); timer=null ; }) } } }
scroll
1 window .addEventListener("scroll" ,throttle(lazyload,200 ))
拓展: IntersectionObserver 通过上面例子的实现,我们要实现懒加载都需要去监听 scroll 事件,尽管我们可以通过函数节流的方式来阻止高频率的执行函数,但是我们还是需要去计算 scrollTop,offsetHeight 等属性,有没有简单的不需要计算这些属性的方式呢,答案就是 IntersectionObserver
。
IntersectionObserver
是一个比较新的 API,可以自动”观察”元素是否可见,Chrome 51+ 已经支持。由于可见(visible)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做”交叉观察器”。我们来看一下它的用法
[]: https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const imgs=document .querySelectorAll("img[data-src]" );const config={ rootMargin :'0px' , threshold :0 } let observer=new IntersectionObserver((entries,self )=> { entries.forEach((entry )=> { if (entry.isIntersecting){ let img=entry.target; let realsrc=img.dataset.src; if (src){ img.src=realsrc; img.removeAttribute('data-src' ) } self.unobserve(entry.target); } }) },config) imgs.forEach((image )=> { observer.observe(image) })