原生实现浏览器支持的图片懒加载方案
概述:因为内部项目运营工具中有遇到处理大量图片在一瞬间请求的场景,在开发阶段遇到了如果不处理图片,不用懒加载的话,浏览器会在一瞬间造成卡顿,用户体验和效果非常差。
解决方案
未调研的
React
三方懒加载库img
图片的属性loading
因为项目采用的是
umi+ts
,而img
属性的loading
并未标准化,还处在实验阶段,但是Chrome 76+
已经支持。代码中直接在jsx
中为img
标签加上loading="lazy"
属性之后会报错,是因为ts
的类型中img
不存在loading
的属性,解决办法是声明一个类型文件,将需要设置的标签属性继承到HTML
属性就好了,别的标签也类似。1
2
3
4
5
6
7
8
9
10
11
12
13// react-unstable-attributes.d.ts
import "react";
declare module "react" {
interface ImgHTMLAttributes<T> extends HTMLAttributes<T> {
loading?: "auto" | "eager" | "lazy";
}
}
// 参数
lazy:延迟加载。
eager:立即加载。
auto:由浏览器来决定是否延迟加载。但是在直接为图片加了
loading
属性之后并没有实现懒加载,后来在调试的时候意外为图片加了width
尺寸之后发现竟然生效了,或许在真实场景之下还需要微调。1
<img loading="lazy" width="90px" />
loading="lazy"
的属性对于别的浏览器的兼容一般,可以利用js
判断,不支持loading
的话使用IntersectionObserver
优雅降级。可参考h5 IntersectionObserver api
IntersectionObserver
提供了一种异步检测目标元素与祖先元素或viewport
相交情况变化的方法。它会注册一个回调函数,每当被监视的元素进入或者退出另外一个元素时(或者 视口 ),或者两个元素的相交部分大小发生变化时,该回调方法会被触发执行。这样,我们网站的主线程不需要再为了监听元素相交而辛苦劳作,浏览器会自行优化元素相交管理。摘自 MDN兼容的
folyfill intersection-observer
伪代码
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
27
28
29// 注册一个回调函数 满足条件的时候自动执行为图片src赋值
const observer = new IntersectionObserver(function(changes) {
changes.forEach(function(element, index) {
// 当这个值大于0,说明满足我们的加载条件了,这个值可通过rootMargin手动设置
if (element.intersectionRatio > 0) {
// 设置图片src属性来加载
element.target.src = element.target.dataset.src;
// 放弃监听,防止性能浪费。
observer.unobserve(element.target);
}
});
});
function initObserver() {
[...document.querySelectorAll('.list-item-img')].forEach(item => {
// 对每个list元素进行监听
observer.observe(item);
});
}
useEffect(() => {
initObserver()
}, [])
// jsx
<img class="list-item-img" data-src="1.png"/>
<img class="list-item-img" data-src="2.png"/>
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!