图片懒加载的集中实现方式
1.基于原生 js 实现图片懒加载
首先需要知道几个高度:
(1)document.documentElement.clientHeight
function getWindowHeight() {
var windowHeight = 0;
if (document.compatMode == "CSS1Compat") {
windowHeight = document.documentElement.clientHeight;
} else {
windowHeight = document.body.clientHeight;
}
return windowHeight;
}
获取屏幕可视区域的
(2)element.offsetTop
获取元素相对于文档顶部的高度。
(3)
document.documentElement.scrollTop
获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离。
然后滑动执行下面的方法:
var imgs = document.querySelectorAll('img');
//offsetTop是元素与offsetParent的距离,循环获取直到页面顶部
function getRealTop(e) {
var realTop = e.offsetTop;
while(e = e.offsetParent) {
realTop += e.offsetTop;
}
return realTop;
}
function lazyLoad(imgs) {
var H = document.documentElement.clientHeight;//获取可视区域高度
var S = document.documentElement.scrollTop || document.body.scrollTop;
for (var i = 0; i < imgs.length; i++) {
if (H + S > getRealTop(imgs[i])) {
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
}
window.onload = window.onscroll = function () { //onscroll()在滚动条滚动的时候触发
lazyLoad(imgs);
}
2.基于 getBoundingClientRect()实现图片懒加载
getBoundingClientRect()
用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。getBoundingClientRect()
是DOM
元素到浏览器可视范围的距离(不包含页面看不见的部分)。该函数返回一个rectObject
对象,该对象有 6 个属性:top
, left
, bottom
, right
, width
, height
;这里的top
、left
和css
中的理解很相似,width
、height
是元素自身的宽高,但是right
,bottom
和css
中的理解有点不一样。right
是指元素右边界距窗口最左边的距离,bottom
是指元素下边界距窗口最上面的距离。
通过这个 API,我们就很容易获取img
元素相对于视口的顶点位置rectObject.top
,只要这个值小于浏览器的高度window.innerHeight
就说明进入可视区域:
function isInSight(el){
const bound = el.getBoundingClientRect();
const clientHeight = window.innerHeight;
return bound.top <= clientHeight;
}
实现代码:
function loadImg(el){
if(!el.src){
const source = el.getAttribute('data-src');;
el.src = source;
}
}
function checkImgs(){
const imgs = document.querySelectorAll('img');
Array.from(imgs).forEach(el =>{
if (isInSight(el)){
loadImg(el);
}
})
}
window.onload = function(){
checkImgs();
}
document.onscroll = function () {
checkImgs();
}
3.基于 IntersectionObserver 实现图片懒加载
我们在平时的开发中,常常需要了解某个元素是否进入了"视口"(viewport),即用户能不能看到它
上图的绿色方块不断滚动,顶部会提示它的可见性。
传统的实现方法是,监听到scroll
事件后,调用目标元素(绿色方块)的getBoundingClientRect()
方法,得到它对应于视口左上角的坐标,再判断是否在视口之内。这种方法的缺点是,由于scroll
事件密集发生,计算量很大,容易造成性能问题。
目前有一个新的 IntersectionObserver API
,可以自动"观察"元素是否可见,Chrome 51+
已经支持。由于可见(visible
)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做交叉观察器
。
var io = new IntersectionObserver(callback, option);
上面代码中,IntersectionObserver
是浏览器原生提供的构造函数,接受两个参数:callback
是可见性变化时的回调函数,option
是配置对象(该参数可选)。
构造函数的返回值是一个观察器实例。实例的observe
方法可以指定观察哪个 DOM
节点。
// 开始观察
io.observe(document.getElementById('container'));
// 停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect();
上面代码中,observe
的参数是一个 DOM
节点对象。
如果要观察多个节点,就要多次调用这个方法。
io.observe(elementA);
io.observe(elementB);
代码实现:
const imgs = document.querySelectorAll('img') //获取所有待观察的目标元素
var options = {}
function lazyLoad(target) {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entrie => {
if (entrie.isIntersecting) {
const img = entrie.target;
const src = img.getAttribute('data-src');
img.setAttribute('src', src)
observer.unobserve(img); // 停止监听已开始加载的图片
}
})
}, options);
observer.observe(target)
}
imgs.forEach(lazyLoad)
4.img.loading=lazy
最后这种相对就简单很多了,它是 Chrome
自带的原生 lazyload
属性。其实支持程度还不是特别好,我们你的应用对于浏览器兼容性要求比较高的话,建议还是先观望一波~
使用方法很简单:
<img src="example.jpg" loading="lazy" alt="">