图片懒加载的原理

1,懒加载的概念

对于页面有很多静态资源的情况下(比如网商购物页面),为了节省用户流量和提高页面性能,可以在用户浏览到当前资源(当前窗口(可视区域)的大小)的时候,再对资源进行请求和加载。

2,懒加载实现的原理

  • 1,使用img标签,scr属性初始为空
  • 2,写一个自定义属性字段,该属性的值写成图片地址
  • 3,当图片在可视区域的范围内的时候,将自定义属性的值作为src的值

代码示例:

<img
  src=""
  lazyload="true"
  data-src="https://t7.baidu.com/itu=1732966997,2981886582&fm=193&f=GIF"
  alt=""
  class="image-item"
/>
  • data-src是我们自己定义的属性字段,它的值为我们要的图片地址
  • lazyload="true"是为了当图片加载出来后将图片不在需要懒加载了。

3,可视区域表示

原理:

使用:document.documentElement.clientHeight 可以获取到当前屏幕的高度。

过程:

当页面发生上滑的时候,可视区域的图片就会发生改变。

当鼠标滚轮滚动的时候,在可视区域的图片就可能出去可视区域了,不在的可能这时候就进来了可视区域。所以我们要写一个监听事件来进行监听

当我们拿到所有的 img 时,利用循环去判断他们是否在可视区域内,在就加载出来,不在就暂时不加载。

需要满足的条件是图片的顶部在可视区域的高度里面,图片的底部也要在可视区域里面,也就是图片没有被划出去。

代码:


//获取可视区域的高度
var viewHeight = document.documentElement.clientHeight;
document.addEventListener("scroll", function() {
  //获取到页面上所有的img
  //判断某个是否进入可视区域
  //如果进入,就把它自身的data-original的值取出来放到src
  var arr = document.querySelectorAll("img[data-src][lazyload]");
  arr.forEach((item) => {
    let rect = item.getBoundingClientRect(); //用于一次性获取某个容器相对于浏览器上下左右的位置
    if (rect.top < viewHeight && rect.bottom >= 0) {
      item.src = item.dataset.src;
      item.removeAttribute("data-src");
      item.removeAttribute("lazyload");
    }
  });
});

获取区域的方法:

  • offsetTop方法: 图片出现在视窗内的情况: offsetTop < clientHeight + scrollTop
  • getBoundingClientRect方法: 图片出现在视窗内的情况: element.getBoundingClientRect().top < clientHeight
  • H5的intersectionObserve方法: intersectionRatio:目标元素的可见比例,即 intersectionRect 占 boundingClientRect 的比例,完全可见时为 1 ,完全不可见时小于等于 0

4,代码实现方式

(1) 使用 getBoundingClientRect方法

// offsetTop
// el.offsetTop - document.documentElement.scrollTop <= viewPortHeight
function isInViewPortOfOne (el) {
    // viewPortHeight 兼容所有浏览器写法
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 
    const offsetTop = el.offsetTop
    const scrollTop = document.documentElement.scrollTop
    const top = offsetTop - scrollTop
    return top <= viewPortHeight
}

document.addEventListener('DomContentLoader', function(){
	let lazyImages = [].slice.call(document.querySelectorAll('#imag.lazy'))
	//限制函数频繁被调用
	let active= false
	const lazyLoad = function(){
	if(active === false){
		active = true
		setTimout(()=>{
			lazyImages.forEach((lazyImage)=>{
				// 判断该图片是否在是视窗中
				if((lazyImage.getBoundingClientReat().top <= window.innetHeight && lazyImage.getBoundingClientReat().bottom >= 0 ) && getComputedStyle(lazyImage).display !== 'none'){
				// 将真实的图片进行赋值
				lazyImage.src = lazyImage.dataset.src
				// 加载完成之后,要为该图片移除lazy这个属性
				lazyImage.classList.remove('lazy')
				// 在lazyImage中将加载后的图片移除
				lazyImages = lazyImages.filter((image)=>{
					return image !== lazyImage
				})
				// 如果所有的待加载图片全都加载完成之后, 移除触发函数
				if(lazyImage.length == 0){
					document.removeEventListener('scroll', lazyLoad);
					wimdow.removeEventListener('resize', lazyLoad)
				}
				}
			});
			active = false
},200)
}
}
	document.addEventListener('scroll', lazyLoad)
	window.addEventListener('resize', lazyLoad)
})

由于用户可以以随心所欲的滑动鼠标滚轮,从而导致scroll事件被触发。在此代码中,将延迟加载的处理过程置于一个异步定时器中,通过修改标志位active的方式来进行限流,其实就是加上了节流操作。
即便这样,也是有骑在的性能问题,因为重复的定时器调用的浪费的。

(2)使用Intersection Observer 方式

对于Intersection Observer 的API,可以通过它来检查目标元素的可见性。作用是:每当因页面滚动或者窗口尺寸发生大小的时候,使得目标元素与设备视窗或者其他元素产生交集的时候,就会触发通过Intersection Observer API配置的回调函数,在该回调函数中进行延迟加载的逻辑处理,会比传统的方式更加简洁而高效。

document.addEvemtListener('DOMContentLoaded', function(){
	let lazyImages = [].slice.call(document.querySelectorAll('img.lazy'))
	// 判断浏览器的兼容性
	if('IntersectionObserver' in window && 'intersectionObserverEnter' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype){
	//新建IntersectionObserver对象 并在其回调函数中实现加载逻辑
	let lazyImageObserver = new IntersectionObserver(funtion(entries, observer){
		entries.foreach((entry)=>{
		// 判断图片是否在视窗内
		if(entry.isIntersecting){
		let lazyImage = entry.target
		lazyImage.src = lazyImage.dataset.src
		// 图片加载完成之后,取消监控重复加载
		lazyImage.classList.remove('lazy')
		lazyImageObserver.unobserver(lazyImage)
}
		})
	})
	// 对每一个懒加载的图片进行监听
	lazyImages.forEach(function(lazyImage){
	lazyImageObservr.observer(lazyImage);
})
}
})

唯一存在的问题,就是兼容性问题,在使用的时候,可以和传统的图片懒加载方式结合起来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值