原生JS的懒加载实现

823 阅读2分钟

在一个网站含有大量的图片,我们在进入一个页面的时候如果一下子全部加载完毕,就会造成很大的资源浪费,而懒加载就是用户浏览到哪里,就加载哪里的图片,这样就可以减少资源的浪费了。


1.懒加载的实现原理

一个img标签如果没有src属性,浏览器就不会发起请求,所以我们在图片没有进入可视区域之前就不会给img标签赋值src属性

2.懒加载的实现方式

(1)使用scrollTop/innerHeight/offsetTop

window.innerHeight:浏览器可视区域高度

document.body.scrollTop || document.documentElement.scrollTop:浏览器滚动条滚过高度(考虑到了兼容)

img.offsetTop:元素距文档顶部的高度 image.png

图片的加载条件: img.offsetTop < window.innerHeight + document.body.scrollTop;

基础代码:

<script type="text/javascript">
	var imgs = document.querySelectorAll('img');
	window.onscroll = function(){
		var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
		var winTop = window.innerHeight;
		for(var i=0;i < imgs.length;i++){
			if(imgs[i].offsetTop < scrollTop + winTop ){
				imgs[i].src = imgs[i].getAttribute('data-src');
			}
		}
	}
</script>

但是我们需要优化一下基础代码,为了防止重复加载,我们需要对基础代码中的函数使用函数节流

<script type="text/javascript">
	var imgs = document.querySelectorAll('img');
	var lazyload = function(){
		var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
		var winTop = window.innerHeight;
		for(var i=0;i < imgs.length;i++){
			if(imgs[i].offsetTop < scrollTop + winTop ){
				imgs[i].src = imgs[i].getAttribute('data-src');
			}
		}
	}
	function throttle(method,delay){
		var timer = null;
		return function(){
			var context = this, args=arguments;
			clearTimeout(timer);
			timer=setTimeout(function(){
				method.apply(context,args);
			},delay);
		}
	}
	window.onscroll = throttle(lazyload,200);
</script>

(2)使用IntersectionObserver方法

基本知识

var io = new IntersectionObserver(callback, option);
//开始观察
io.observe(document.getElementById('example'));
//停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect();

callback是可见性变化时的回调函数,option是配置对象。这个构造函数的返回值是一个观察器实例。构造函数的返回值是一个观察器实例,实例的observe方法可以指定观察哪个DOM节点。

上面代码中,observe的参数是一个DOM节点对象。如果要观察多个节点,就要多次调用这个方法。callback函数的参数(entries)是一个数组,每个成员都是一个IntersectionObserverEntry对象。 举例来说,如果同时有两个被观察的对象的可见性发生变化,entries数组就会有两个成员。intersectionRatio:目标元素的可见比例,完全可见时为1,完全不可见时小于等于0。

完整代码

<script type="text/javascript">
	//获取观察器实例  changes是被观察的对象数组
	var observer = new IntersectionObserver(function(changes){  
		console.log(changes);
		changes.forEach(function(index,item){
			if(item.intersectionRatio > 0 && item.intersectionRatio < 1)
				//target:被观察的目标元素,是一个 DOM 节点对象
				item.target.src = item.target.dataset.src;
		});
	});
	function addObserver(){
		var listItems = document.querySelectorAll('.img-item');
		listItems.forEach(function(item){
			//实例的observe方法可以指定观察哪个DOM节点
			//开始观察  observe的参数是一个 DOM 节点对象
			observer.observe(item);
		});
	}
	addObserver();
</script>