图片懒加载的意义
虽然当代浏览器在渲染 DOM 树的时候。遇到 img 并不会阻碍 DOM 树的渲染(浏览器会开辟HTTP线程请求图片资源文件),但是在生成 RENDER TREE 后,浏览器进行渲染的时候,会把渲染树和图片一起进行绘制,这时就会遇到一些影响性能的(影页面第一次加载的速度)问题:
- 如果请求的图片资源过多,我们同时可以开辟的HTTP线程只有6个,这样图片资源预先的加载,会影晌其他资源的请求速度;
- 第一次绘制页面的时候,如果开始绘制图片,也需要消耗很多的时间,这样也影晌页面第一次打开的速度。
所以对于这种情况:
- 我们一般都采用图片的懒加载(开始需要展示图片的位置,我们基于默认图或者一个空白的盒子占位,真实图片不加载,只有当页面的一次渲染完以及滚动到当前所在的区域时候,冉去加载真实的图片);
- 我们可以把图片 base64(虽然也会慢一,但是总比不做强多)。
getBoundingClientRect
getBoundingClientRect 用于获取某个元素相对于视窗的位置集合。集合中有top, right, bottom, left等属性。
clientRect = lazyImageBox.getBoundingClientRect();
- clientRect.top:元素上边到视窗上边的距离;
- clientRect.right:元素右边到视窗左边的距离;
- clientRect.bottom:元素下边到视窗上边的距离;
- clientRect.left:元素左边到视窗左边的距离。
盒子底边距离视口上面的距离 bottom 小于等于视口的高度,再开始加载图片。
let lazyImageBox = document.querySelector('.lazyImageBox'),
lazyImage = lazyImageBox.querySelector('img');
const singleLazy = function singleLazy() {
let trueImg = lazyImage.getAttribute('lazy-image');
lazyImage.src = trueImg;
lazyImage.onload = () => {
// 真实图片加载成功
lazyImage.style.opacity = 1;
};
lazyImageBox.isLoad = true;
};
const lazyFunc = function lazyFunc() {
// 防止重复处理
if (lazyImageBox.isLoad) return;
let A = lazyImageBox.getBoundingClientRect().bottom,
B = document.documentElement.clientHeight || document.body.clientHeight;
if (A <= B) {
singleLazy();
}
};
// window.onscroll = lazyFunc; //默认浏览器会在最快的反应时间内,监听到scroll事件的触发,从而执行lazyFunc这个方法,这样导致触发频率太高了 -> 节流处理
window.onscroll = throttle(lazyFunc);
IntersectionObserver
IntersectionObserver 可以自动"观察"元素是否可见。本质是目标元素与视口产生一个交叉区,所以这个 API 叫做"交叉观察器"。
它的用法非常简单。
let ob = new IntersectionObserver(callback, option);
上面代码中,IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(该参数可选)。
构造函数的返回值是一个观察器实例。实例的observe方法可以指定观察哪个 DOM 节点。
// 开始观察
ob.observe(document.getElementById('example'));
// 停止观察
ob.unobserve(element);
// 关闭观察器
ob.disconnect();
上面代码中,observe的参数是一个 DOM 节点对象。如果要观察多个节点,就要多次调用这个方法。
callback 参数
目标元素的可见性变化时,就会调用观察器的回调函数callback。
callback一般会触发两次。一次是目标元素刚刚进入视口(开始可见),另一次是完全离开视口(开始不可见)
let ob = new IntersectionObserver(changes => {
// changes 是一个数组,包含所有监听的DOM元素和视口的交叉信息
let item = changes[0],
{
isIntersecting,
target
} = item;
});
callback函数的参数(changes)是一个数组,每个成员都是一个IntersectionObserverEntry对象。举例来说,如果同时有两个被观察的对象的可见性发生变化,changes 数组就会有两个成员。
IntersectionObserverEntry 对象
IntersectionObserverEntry提供观察元素的信息,有八个属性。
1. boundingClientRect:目标元素的矩形信息;
2. intersectionRatio:相交区域和目标元素的比例值 ;
3. intersectionRect:目标元素和视窗(根)相交的矩形信息 可以称为相交区域;
4. isIntersecting:目标元素当前是否可见 Boolean值 可见为true;
5. rootBounds:根元素的矩形信息,没有指定根元素就是当前视窗的矩形信息;
6. target:观察的目标元素;
7. time:返回一个记录从IntersectionObserver的时间到交叉被触发的时间的时间戳。
intersectionRect/boundingClientRect:不可见时小于等于0;
Option 对象
IntersectionObserver构造函数的第二个参数是一个配置对象。它可以设置以下属性。
threshold属性决定了什么时候触发回调函数。它是一个数组,每个成员都是一个门槛值,默认为[0],即交叉比例(intersectionRatio)达到0时触发回调函数。
用户可以自定义这个数组。比如,[0, 0.25, 0.5, 0.75, 1]就表示当目标元素 0%、25%、50%、75%、100% 可见时,会触发回调函数。
let lazyImageBox = document.querySelector('.lazyImageBox'),
lazyImage = lazyImageBox.querySelector('img');
const singleLazy = function singleLazy() {
let trueImg = lazyImage.getAttribute('lazy-image');
lazyImage.src = trueImg;
lazyImage.onload = () => {
lazyImage.style.opacity = 1;
};
};
// 使用DOM监听器 IntersectionObserver:监听一个或者多个DOM元素和可视窗口的交叉信息
let ob = new IntersectionObserver(changes => {
// changes是一个数组,包含所有监听的DOM元素和视口的交叉信息
let item = changes[0],
{
isIntersecting,
target
} = item;
if (isIntersecting) {
// 完全出现在视口中了
singleLazy();
ob.unobserve(lazyImageBox); //加载真实图片后,移除对盒子的监听
}
}, {
threshold: [1]
});
ob.observe(lazyImageBox);
总结
IntersectionObserver 是新的浏览器 API , 可以更方便的实现图片延迟加载。但是 getBoundingClientRect 比起 IntersectionObserver 有更好的兼容性,因为IE无法兼容,所以要在IE实现这些功能,还是得老老实实使用基于 scroll 事件使用 getBoundingClientRect 来整。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!