懒加载的模块化实现
问题背景:
有时打开一个页面,要很长时间页面才能响应,这是因为通常对于页面响应的JS,需要等待页面的元素上全部加载完毕后,才能执行;
图片加载需要的时间都比较长,对于图片较多的页面设计,如果不对元素进行设置的话,就需要将所有图片加载完后,页面才能响应
这不仅花费时间较长;同时也会浪费流量,可能用户并不需要看后面的许多内容;
懒加载就是针对这种情况的一个解决方法,对于页面上的元素,当进入视野中才进行加载,这样就减少了页面打开加载的时间,同时也节省了不必要的流量。
对于一些需要实时更新内容的元素,也可利用懒加载,在元素进入视野时,再刷新;
场景模拟:
模拟一个场景,既需要加载图片也需要实时更新页面内容
image.png
上半部是需要实时更新文本的部分,每当文本框进入视野时,文本内容会更新;
下方是需要加载的多个图片
1.模块化的实现
页面中不同的模块需要的处理方式不同,文本信息重新进入视野需要刷新内容;但图片即便多次翻动页面进入视野,也不需要重复加载,只需要一次就够了;
所以,为了更好的模块兼容性,使用面向对象的方法来实现懒加载的模块,针对不同的需求,只需要进行相应的实例化,就可以了
function showImg($node) {
$node.attr('src', $node.attr('data-src'))
}
var Lazy = (function() {
return {
realTime: function($targets, callback) {
$targets.each(function(idx, target) {
new Exposure($(target), false, callback);
})
},
once: function($targets, callback) {
$targets.each(function(idx, target) {
new Exposure($(target), true, callback);
})
}
}
})()
Lazy.realTime($('#hello'), function($node) {
$node.text($node.text() + '123');
});
Lazy.realTime($('#world'), function($node) {
$node.text($node.text() + '456');
});
Lazy.once($('.container img'), function($node) {
showImg($node);
});
function Exposure($target, once_check, callback) {
this.$target = $target;
this.once_check = once_check;
this.callback = callback;
this.loaded = false;
this.bind();
this.check();
}
对于不同的模块,通过不同的接口进行实例化,并提供相应的回调来处理模块进入视野后的处理方法;
值得说明的一点是,Lazy提供的接口中,是利用了数组的方法.each,来对每个元素都进行了一次Exposure的对象创建。
这是考虑到对于批量的图片,只需要一次全部选择,即可对内部每一个图片进行实例化了,使用更方便,即便是内部只有一个元素的文本,也可通用,兼容性更好。但缺点是对象的重复创建太多,每个img都创建了一个Exposure对象
2.模块进入视野的判断方法
Exposure.prototype.isVisible = function($node) {
var windowHeight = $(window).height();
var offsetTop = $node.offset().top;
var nodeHeight = $node.height();
var scrollTop = $(window).scrollTop();
if (windowHeight + scrollTop > offsetTop + nodeHeight && scrollTop < offsetTop + nodeHeight) {
return true
}
return false
}
滚动的高度加上窗口的高度,大于目标到页面顶端的高度,说明进入窗口。
同时,滚动高度小于目标到页面的offsetTop,说明还停留在窗口中,没出去,两个条件都要满足
3.判断元素是否加载过
Exposure.prototype.isLoaded = function($node) {
if ($node.attr('loaded')) {
return true;
} else {
$node.attr('loaded', 'true');
return false;
}
}
通过判断元素属性“loaded”,来判断元素是否加载过
源码
演示
可以看到,当反复滚动页面,文本框重新进入窗口后,文本内容改变
在showImg中console.log,在控制台可以看到,当图片加载过一次之后,再滚动页面,load-img-go不再增加