1、目标
- 从浏览器底层渲染机制分析懒加载的意义
- 最初基于JS盒模型实现的懒加载方案
- 基于getBoundingClientRect的进阶方案
- 手撕Lodash源码中的debounce(函数防抖)
- 手撕Lodash源码中的throttle(函数节流)
- 终极方案:IntersectionObserver
- 未来设想:img.loading=lazy
2、从浏览器底层渲染机制分析懒加载的意义
* 为啥要做图片的延迟加载
* 浏览器渲染页面
* 1.构建DOM树
* 2.构建CSSOM树
* 3.生成RENDER TREE
* 4.布局
* 5.分层
* 6.珊格化
* 7.绘制
* 构建DOM树中如果遇到img
* 老版本:阻碍DOM渲染
* 新版本:不会阻碍 每一个图片请求都会占用一个HTTP(浏览器同时发送的HTTP 6个)
* 拿回来资源后会和RENDER TREE一起渲染
* …
* 开始加载图片,一定会让页面第一次渲染速度变慢(白屏)
* 图片延迟加载:第一次不请求也不渲染图片,等页面加载完,其他资源都渲染好了,再去请求加载图片
*/
3、
// 核心代码
// 加载条件:盒子底边距离BODY距离 < 浏览器底边距离BODY的距离
// 方法一:
let B = utils.offset(lazyImageBox).top + lazyImageBox.offsetHeight,
A = winH + document.documentElement.scrollTop;
if (B <= A) {
lazyImg(lazyImageBox);
}
/*
*/
// 方法二:
// let {
// bottom
// } = lazyImageBox.getBoundingClientRect();
// if (bottom <= winH) {
// lazyImg(lazyImageBox);
// }
// 方法三
// IntersectionObserver 监听DOM对象,当DOM元素出现和离开视口的时候触发回调函数
// let lazyImageBoxs,
// observer = new IntersectionObserver(changes => {
// changes.forEach(item => {
// let {
// isIntersecting,
// target
// } = item;
// if (isIntersecting) {
// lazyImg(target);
// observer.unobserve(target);
// }
// });
// });
// 方案四: 每个图片加一个 loading="lazy" 兼容性差
function lazyImg(lazyImageBox) {
let img = lazyImageBox.querySelector('img'),
trueImg = img.getAttribute('data-image');
img.src = trueImg;
img.onload = function () {
// 图片加载成功
utils.css(img, 'opacity', 1);
};
img.removeAttribute('data-image');
}