背景
网页中存在很多存储于腾讯云的CDN形式的高清图,大多为PNG格式,大小从几百kb到几十M不等,张数由1张到上百张不等。由此导致页面的图片加载缓慢。
前端解决方案:
- png格式转为webp格式(无损压缩)
- 图片按需加载。
针对以上两个方案需要注意的点如下:
- webp格式的兼容性处理
a):使用picture & source标签,source标签可以设定
<picture>
<source type="MIME-TYPE" srcset="./image.webp"></source>
<img src="./image.png">
</picture>
b): 使用img标签的onError属性: 当webp格式无法展示时使用该模式
<img
src="'./image.webp"
onError={({ currentTarget = {} }: any) => {
currentTarget.onerror = null;
currentTarget.src = './image.png';
}}
/>
c): 使用js模式来处理onError的情况,和上一种方法原理一致
const img = new Image();
img.src = './image.webp';
img.onerror = function ({ currentTarget = {} }: any) {
currentTarget.onerror = null;
currentTarget.src = './image.png';
};
- 图片按需加载的更优方案
方案一:
一般来说,提到图片的懒加载(按需加载),网上很多方案都是通过计算图片距离浏览器顶部的距离,对比页面可视区域高度+滚动条滚动距离比较。如果大于,说明还不需要加载图片,如果小于或等于,说明这张图片即将要被展示,这时候就需要去加载图片。
详细步骤:
const scrollTopHeight = document.documentElement.scrollTop ;
const currentClientHeight = document.documentElement.clientHeight;
const imageOffsetTop = imgs[i].offsetTop;
if(documentElement <= scrollTopHeight + currentClientHeight ) {
imgs[i].src = imgs[i].getAttribute('data-src')
}
<img data-src="image-path" />
以上获取img是否出现在可视区域的方案还有:
element.getBoundingClientRect()
bound.top <=docment.documentElement.clientHeight
详情可参考:MDN: getBoundingClintRect
但是以上的方式有个弊端:不断地监听页面的滚动,对页面的性能有一定的影响。
所以我们可以采取
方案二:
insterSetionObserver()
来监听元素是否出现在可视区域。
很多地方说这个方法兼容性不好, 但事实上,根据我大部分的场景,不觉得这个兼容性有啥问题,可以根据自己的需求来判定是否适用。
详细步骤:
const callback = (entires) => {
entires.forEach(item => {
if(item.isIntersecting) {
item.target.setAttribute("src", item.target.getAttribute('data-src'))
observer.unobserve(item.target)
}
})
}
const observer = new intersectionObserver(callback);
imgs.forEach(img => observer.observe(img))