项目中有一个图片列表的页面,每个页面大概有几十张图片,图片加载比较慢的时候就都是白屏看起来很不友好,于是就想给图片增加一个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 demo18