图片懒加载几个版本的实现对比
大厂技术 高级前端 Node进阶
点击上方 程序员成长指北,关注公众号
回复1,加入高级Node交流群
背景
图片懒加载是针对图片加载时机的一种优化,在一些图片量比较大的网站(比如电商网站首页,或者团购网站、小游戏首页等),如果我们尝试在用户打开页面的时候,就把所有的图片资源加载完毕,那么很可能会造成白屏、卡顿等现象,因为图片真的太多了,一口气处理这么多任务,浏览器做不到啊!
懒加载是为了让浏览器只加载可视区内的图片,可视区外的大量图片不进行加载,当页面滚动到后面去的时候再进行加载。这样做有很多好处可以增加首屏加载的速度,毕竟,用户点开页面的瞬间,呈现给他的只是首屏,我们只要把首屏的资源图片加载处理就可以了,至于下面的图片,当用户下滑当当前位置的时候,在加载出来也是没问题的,对于性能压力也小了,用户体验也没有变差。
解答
图片懒加载的原理就是需要知道图片是否在可视区内了,当图片到达可视区内就需要去请求对应的图片加载出来
页面中的img
标签一般如下写
class="lazyload" src="placeholder.jpg" src="real_image.jpg" />
其中src首先赋值一个占位的图片,一般是一个很小的图片,进行占位,src是实际需要展示的图片,原理就是当图片在可视区内的时候将src的图片选渲染出来即可。
1、原生实现
Chrome 76 将原生支持图片的惰性加载,支持对img和iframe进行延迟加载,只需要将loading属性设置为lazy即可。
<img src="celebration.jpg" loading="lazy" alt="..." />
<iframe src="video-player.html" loading="lazy">iframe>
原生实现的好处是,不需要任何脚本,纯原生HTML即可,简单方便,支持多种属性
lazy:对资源进行延迟加载。 eager:立即加载资源。 auto:浏览器自行判断决定是否延迟加载资源。
原生的坏处就是在于浏览器的支持率不是很高,将来肯定是非常好的。
我们知道由于浏览器的支持率不是很好,上面的方案固然很好,但是使用的并不是很多,所以下面介绍几种更加常见的懒加载方案。
2、Element.getBoundingClientRect()
getBoundingClientRect
返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合, 即:是与该元素相关的CSS 边框集合 。DOMRect 对象包含了一组用于描述边框的只读属性——left、top、right和bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。
有了这个API后我们很同意获取图片的top值,当top值小于可视区的高度的时候就可以任何图片进入了可视区,直接加载图片即可
element.getBoundingClientRect().top < document.documentElement.clientHeight
由于需要在滚动的时候去监听图片的位置,所以我们需要使用到window.onscroll
事件,我们在事件内部处理相关的逻辑即可。
3、通过相对计算获取元素位置
通过document.documentElement.clientHeight获取屏幕可视窗口高度。 通过element.offsetTop获取元素相对于文档顶部的距离。 通过document.documentElement.scrollTop获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离。然后判断2-3<1是否成立,如果成立,元素就在可视区域内。
element.offsetTop - document.documentElement.scrollTop < document.documentElement.clientHeight
此方法也需要在滚动的时候去监听图片的位置,所以我们需要使用到window.onscroll
事件,我们在事件内部处理相关的逻辑即可。
4、使用IntersectionObserver
const observer = new IntersectionObserver(callback, observerConfig)
const imgList = document.querySelectorAll(".lazyload");
const observer = new IntersectionObserver(entries => {
entries.forEach(item => {
if (item.isIntersecting) {
item.target.src = item.target.dataset.origin; // 判断在可视区了,把data-origin的值放到src
observer.unobserve(item.target); // 已经加载过的图片停止进行监听
}
});
});
imgList.forEach(item => observer.observe(item));
补充
1、优化
由于上面某些情况是需要使用到window.scroll
事件的,所以我们可以增加节流来减少事件处理函数的调用次数。假设我们判断是否可视区逻辑为函数loadImage
那么我们可以如下处理。
window.onscroll = throttle(loadImage, 500)
2、拓展
上面后续三种方法不仅仅可以使用在图片的懒加载上面,其实所有可以懒加载的地方都可以通过这种方式进行判断,比如列表分页加载,我们可以通过这种方式进行判断是否需要进行下一页的加载,比如我们需要埋曝光埋点的时候,可以通过这种方法判断元素是否曝光,进行埋点事件的触发。
我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。
“分享、点赞、在看” 支持一波👍