本文原创,转载请注明出处
前几天修改了之前APP的一些功能,发现图片的加载太慢了,而且一个页面显示太多图片的话其他js什么的也都延迟了加载,造成事件方法未加载、操作无效果,用户体验差。原因除了图片显示的有点多之外还有我们的服务器限制的有下载速度,所以考虑到了图片的懒加载(这个思路也可以实现上拉加载)。
下面我只是简单实现了一下效果,抛砖引玉,想一次加载一个屏幕那么多图片的话也不难,需要的可以另外加入判断即可,这里就不再赘述:
2017-05-15 第一次编辑
2017-11-24 更新
看了一下之前写的这篇博客,发现有些地方写的比较马虎或者说瞎写,因为那个时候以为这样的需求已经足够用了,闲来无事看了下发现问题很大。已经更新,如果发现还有错误请留言。
2019-1-29 更新
隔段时间翻一下自己写的东西,果然有不一样的感触,当时写的只是很粗糙的东西,跟之前看到的朋友说声抱歉,现在再优化一下。
2020-5-20 更新
init()加入了params.diff:距img元素显露出的距离,params.defaultUrl:默认站位图;增加了图片显示的过渡效果。
CSS代码
只是设置图片的一些样式:
<style>
*{
margin: 0;
padding: 0;
}
div {
height: 250px;
text-align: center;
}
img{
width: 50px;
height: 50px;
opacity: 0;
transition: opacity 1s ease-in;
}
</style>
HTML代码
1.png是一个1*1px的透明图或者带有logo,这样加载快,测试效果的话无所谓,只要能区分开路径不一样就行,jpg 格式图是实际应该加载的图片路径,data-url存放图片实际路径:
<div>
<img class="lazyImg" data-url="https://www.runoob.com/images/compatible_ie.gif" alt="">
</div>
<div>
<img class="lazyImg" data-url="https://www.runoob.com/images/compatible_firefox.gif" alt="">
</div>
<div>
<img class="lazyImg" data-url="https://www.runoob.com/images/compatible_opera.gif" alt="">
</div>
<div>
<img class="lazyImg" data-url="https://www.runoob.com/images/compatible_chrome.gif" alt="">
</div>
<div>
<img class="lazyImg" data-url="https://www.runoob.com/images/compatible_safari.gif" alt="">
</div>
JS代码
原理:
- 初始进入页面,计算要加载哪些图片,创建Image,加载图片,让要显示的图片路径改为实际路径;
- 滚动至图片要显示出来时(diff设置滚动至距图片多少距离开始加载),执行 1 的逻辑:
<script>
/*
* init() 在初始化时调用, params.diff:距img元素显露出的距离,params.defaultUrl:默认站位图
*
* loadOriginalImage() 加载占位图
*
* firstLoad() 是首次进入页面加载图片的方法
*
* bindScroll() 是绑定滚动
* */
var loadImg = {
diff: 50, // 距img元素显露出的距离
defaultUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC',
init: function (params) {
this.loadOriginalImage();
var self = this;
// 替换默认值
if (params) {
this.diff = params.diff || this.diff;
this.defaultUrl = params.defaultUrl || this.defaultUrl;
}
window.onscroll = function () {
self.bindScroll();
};
},
// 加载占位图
loadOriginalImage: function () {
var self = this;
[].slice.call(document.querySelectorAll('.lazyImg')).forEach(function (e) {
e.src = self.defaultUrl;
});
this.firstLoad();
},
firstLoad: function () {
//设备可用高度
var availHeight = window.screen.availHeight;
//遍历#one下的img,然后替换路径
for(var x = 0;x < document.querySelectorAll('.lazyImg').length;x++){
var el = document.querySelectorAll('.lazyImg')[x];
//如果是首屏显示的图片
if (el.offsetTop < availHeight) {
var imgUrl = el.dataset.url;
var img = new Image();
img.src = imgUrl;
img.onload = (function (e) {
el.src = el.dataset.url;
el.style.opacity = 1;
})();
} else {
break;
}
}
},
bindScroll: function () {
// 设备可用高度
var availHeight = window.screen.availHeight;
// 滚动的高度
var scrollHeight = document.documentElement.scrollTop;
// 判断如果显示出来了#two
for (var x = 0; x < document.querySelectorAll('.lazyImg').length; x++) {
var el = document.querySelectorAll('.lazyImg')[x];
// img距顶部的高度
var contentTop = el.offsetTop;
// 判断此时显示出img
if (scrollHeight + this.diff > contentTop - availHeight) {
// 如果data-url 不等于 src,说明图片没有加载到
if (el.dataset.url !== el.src) {
var imgUrl = el.dataset.url;
var img = new Image();
img.src = imgUrl;
img.onload = (function () {
el.src = el.dataset.url;
el.style.opacity = 1;
})();
}
}
}
}
};
loadImg.init({diff: 150});
</script>
完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport" />
<title>图片懒加载</title>
</head>
<style>
*{
margin: 0;
padding: 0;
}
div {
height: 250px;
text-align: center;
}
img{
width: 50px;
height: 50px;
opacity: 0;
transition: opacity 1s ease-in;
}
</style>
<body>
<div>
<div>
<img class="lazyImg" data-url="https://www.runoob.com/images/compatible_ie.gif" alt="">
</div>
<div>
<img class="lazyImg" data-url="https://www.runoob.com/images/compatible_firefox.gif" alt="">
</div>
<div>
<img class="lazyImg" data-url="https://www.runoob.com/images/compatible_opera.gif" alt="">
</div>
<div>
<img class="lazyImg" data-url="https://www.runoob.com/images/compatible_chrome.gif" alt="">
</div>
<div>
<img class="lazyImg" data-url="https://www.runoob.com/images/compatible_safari.gif" alt="">
</div>
</div>
<script>
/*
* init() 在初始化时调用, params.diff:距img元素显露出的距离,params.defaultUrl:默认站位图
*
* loadOriginalImage() 加载占位图
*
* firstLoad() 是首次进入页面加载图片的方法
*
* bindScroll() 是绑定滚动
* */
var loadImg = {
diff: 50, // 距img元素显露出的距离
defaultUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC',
init: function (params) {
this.loadOriginalImage();
var self = this;
// 替换默认值
if (params) {
this.diff = params.diff || this.diff;
this.defaultUrl = params.defaultUrl || this.defaultUrl;
}
window.onscroll = function () {
self.bindScroll();
};
},
// 加载占位图
loadOriginalImage: function () {
var self = this;
[].slice.call(document.querySelectorAll('.lazyImg')).forEach(function (e) {
e.src = self.defaultUrl;
});
this.firstLoad();
},
firstLoad: function () {
//设备可用高度
var availHeight = window.screen.availHeight;
//遍历#one下的img,然后替换路径
for(var x = 0;x < document.querySelectorAll('.lazyImg').length;x++){
var el = document.querySelectorAll('.lazyImg')[x];
//如果是首屏显示的图片
if (el.offsetTop < availHeight) {
var imgUrl = el.dataset.url;
var img = new Image();
img.src = imgUrl;
img.onload = (function (e) {
el.src = el.dataset.url;
el.style.opacity = 1;
})();
} else {
break;
}
}
},
bindScroll: function () {
// 设备可用高度
var availHeight = window.screen.availHeight;
// 滚动的高度
var scrollHeight = document.documentElement.scrollTop;
// 判断如果显示出来了#two
for (var x = 0; x < document.querySelectorAll('.lazyImg').length; x++) {
var el = document.querySelectorAll('.lazyImg')[x];
// img距顶部的高度
var contentTop = el.offsetTop;
// 判断此时显示出img
if (scrollHeight + this.diff > contentTop - availHeight) {
// 如果data-url 不等于 src,说明图片没有加载到
if (el.dataset.url !== el.src) {
var imgUrl = el.dataset.url;
var img = new Image();
img.src = imgUrl;
img.onload = (function () {
el.src = el.dataset.url;
el.style.opacity = 1;
})();
}
}
}
}
};
loadImg.init({diff: 150});
</script>
</body>
</html>