项目中有一个图片列表的页面,每个页面大概有几十张图片,图片加载比较慢的时候就都是白屏看起来很不友好,于是就想给图片增加一个loading效果,但是又不想改动原有代码,于是我想了一个通用的方案,通过js代码切入直接全局修改实现图片的loading效果。
经过实验和思考,我最终实现的方案是:在dom加载完毕后,图片加载完成之前,这中间的时刻触发我的操作,操作内容是获取需要进行loading效果的图片元素即img标签,将img的图片地址取出,替换成loading效果的图片,这时新建一个Image对象,将取出的原图片地址通过新建的Image对象去加载图片资源,当图片资源加载完毕之后,把原图地址设置回原来的img元素。说起来有点绕,直接看代码吧。
<script>
//配置loading中的图片
let imgLoading = "img/img-loading.gif";
//配置加载失败的图片
let imgFail = "img/img-no.jpg";
//提前加载需要的图片资源
new Image().src = imgLoading;
new Image().src = imgFail;
/**
* 处理图片方法
* @param obj 处理的图片元素
*/
function handleImg(obj){
obj.onerror = function () {
obj.src = imgFail
};
setTimeout(function() {
if (!obj.complete) {
//新建一个临时的图片元素
let temp = new Image();
//原图片路径赋值给临时图片元素
temp.src = obj.getAttribute("src");
//原图片改成loading图片
obj.setAttribute("src", imgLoading);
//临时图片元素设置加载完成回调函数
temp.onload = function () {
obj.src = temp.src
};
}
},1000);
}
//dom结构加载完后对所有img节点进行loading处理
$(document).ready(function(){
let imgList = document.getElementsByTagName('img');
for (let img of imgList) {
handleImg(img)
}
});
</script>
将上述代码块放于head标签中,自行配置loading效果的图片和图片加载失败之后显示的图片资源路径,即imgLoading和imgFail两个变量的值。最终效果如图:(第一张图片是正常显示的图片;第二张图片是我的loading状态图,一个挺好看的动图;第三张图片是加载失败之后的图片)
代码解释:
1、代码切入点使用的是$(document).ready(function(){});
因为在这一时刻,dom节点已经都加载完毕了,但是图片资源不一定全部加载完毕,符合我方案要求。这一块可以使用下方代码进行测试。
$(document).ready(function(){
let imgList = document.getElementsByTagName('img');
for (let img of imgList) {
img.onload=function(){
console.log("图片加载结束");
};
}
console.log("document.ready执行结束");
});
2、因为loading状态的图片肯定要早于具体的图片先加载,否则loading图片替换之后还是白屏,没有意义。因此需要如下代码提前加载loading图片资源。
//提前加载需要的图片资源
new Image().src = imgLoading;
new Image().src = imgFail;
3、假如图片加载很快,在1秒内已经加载完毕了,那这个时候就没必要再替换成loading图片,然后再替换回正常图片,按照我的理解,只有那些大于1秒还没加载好的图片才需要loading效果,所以我在handleImg方法里面加了个timeout方法,解决图片会闪一下loading效果的问题。这里的1秒时间可以自定义。
完整的demo见:https://gitee.com/lqccan/blog-demo/tree/master/%E5%89%8D%E7%AB%AF/%E5%9B%BE%E7%89%87loading