今天我们来学习如何封装一个预加载图片的方法
首先,我们确定一下这个方法的功能
1、可以加载一张图,也可以加载多张图片
2、如果需要设定全部基础路径,可以设置参数basePath
3、如果需要设定将缺省扩展名图片补足,可以设置suffix参数
4、可以传入完成调用的回调函数,当不传入这个回调函数时,可以侦听IMG_FINISH_EVENT事件,获取事件抛发出去finishList,
5、如果传入是一张图地址,返回就是这一张,如果传入是数组地址,就会返回多个图片的数组
6、当图片地址错误时,插入对应的null
解决思路:
1、判断sourceArr是否是字符串,如果是字符串,则让它变为数组,并且让这个字符串作为唯一元素,目的是统一所有的给入地址都是数组,方便调用
2、判断basePath是否是字符串,判断当前这个basePath尾部是不是/结束,如果不是/结束,增加/然后遍历地址数组,将basePath添加在地址数组的前面,如果传入的地址前面有/,就将原来的/去掉
3、判断suffix是否是字符串,然后判断suffix的第一位是否是.,如果不是.,在前面增加.然后遍历地址数组,判断地址数组中每个地址是否在倒数第4位或者倒数5是否是.如果是,就不需要加suffix,如果不是在地址后增加suffix
4、创建一个新图片元素,并且设置这个图片元素的地址为sourceArr的第0项开始加载,并且侦听事件load和error如果加载完成执行loadHandler,加载失败执行errorHandler。因为我们在后面是以当前这个图片为中心载体,不断更改其地址,使其不断加载新的图片,去激活load事件执行对应的方法,因此,这个图片载体上存储一些数据,这些数据包括当前加载图片的为n,当前加载完图片存储的数组finishList,当前需要加载图片地址数组,加载完成,后需要执行的回调函数finishHandler,全部存储在这个图片对象中
方法:loadImage
参数:
1、sourceArr Array或者String 加载的图片地址列表或者一张图片地址
Array 加载多张图片地址
String 加载一张图片,为了后续使用,我们统一使用数组,所以如果这个是String,
将设置sourceArr是空数组,并且这个字符串放在这个数组中,成为数组的唯一元素
2、finishHandler Function 或者 undefined 完成执行回调函数
Function 当图片预加载完成,通过回调该函数,将加载完成的图片传回给这个数组参数中
undefined 在后面将会通过事件抛发机制将数据传回
3、basePath string 基础路径
为了将传入地址中路径补齐基础路径
4、suffix string 扩展名
为了将传入地址中补齐扩展名
var Utils=(function(){
return {
IMG_FINISH_EVENT:"img_finish_event",
loadImage:function(sourceArr,finishHandler,basePath,suffix){
if(typeof sourceArr==="string") sourceArr=[sourceArr];
if(basePath && typeof basePath==="string"){
basePath=basePath.endsWith("/") ? basePath : basePath+"/";
sourceArr=sourceArr.map(function(item){
item=String(item);
return basePath+(item.startsWith("/") ? item.slice(1) : item);
})
}
if(suffix && typeof suffix==="string"){
suffix=suffix.startsWith(".")? suffix : "."+suffix;
sourceArr=sourceArr.map(function(item){
item=String(item);
// if(item.endsWith(".",item.length-3) || item.endsWith(".",item.length-4))
if(![item.slice(-5,-4),item.slice(-4,-3)].includes("."))item+=suffix;
return item;
})
}
var img=new Image();
img.src=sourceArr[0];
img.n=0;
img.finishList=[];
img.sourceArr=sourceArr;
img.finishHandler=finishHandler;
img.addEventListener("load",this.loadHandler);
img.addEventListener("error",this.errorHandler);
}
}
2、加载完成处理思路
1、当加载完成后,将当前图片克隆复制的新图片放入到当前图片的载体属性finishList(完成后图片数组)中
2、判断加载下一张图片是否完成,如果完成了,返回true就直接跳出
加载完成执行的函数
参数
e 加载完成的事件对象event load
这个函数中的this是加载图片的侦听对象,就是上一个函数中img
loadHandler:function(e){
this.finishList.push(this.cloneNode(false));
if(Utils.nextImg(this)) return;
},
2、加载失败处理思路
1、先判断加载下一张图片是否完成,如果加载完成直接跳出
2、如果没有完成,把null添加在图片数组中
加载失败执行的函数
参数
e 加载完成的事件对象event error
这个函数中的this是加载图片的侦听对象,就是上一个函数中img
errorHandler:function(e){
this.finishList.push(null);
if(Utils.nextImg(this)) return;
},
2、加载图片过程处理思路
1、增加img的需要加载第几张图片n
2、如果当前需要加载的图片的下标超过了数组的长度
删除当前图片的加载和失败事件
判断当前图片属性finishHandler这个回调函数是否是函数,如果是函数,执行这个函数并且将
当前加载完成的图片数组当参数传入
如果这个finishHandler不是函数,我们通过事件的抛发,发出Utils.IMG_FINISH_EVENT这个
字符串的事件,并且在这个事件对象中带入属性finishList数据结果
如果当前这个数组,仅有一个元素,我们直接返回这个元素,如果有多个元素时,才返回数组
抛发事件的对象是针对document,因为在页面中document用存在并且唯一
如果全部加载完成返回true,以方便判断是否继续加载下一张图
如果没有加载完成,重新设置这个图片的地址为下一个地址,并且返回false
加载下一张图片,传入参数当前图片
img 就是loadImage函数中img,这个加载完成和失败事件函数中this
nextImg:function(img){
img.n++;
if(img.n>img.sourceArr.length-1){
img.removeEventListener("load",Utils.loadHandler)
img.removeEventListener("error",Utils.errorHandler)
if(typeof img.finishHandler==="function") img.finishHandler(img.sourceArr.length===1 ?img.finishList[0] : img.finishList);
else{
var evt=new Event(Utils.IMG_FINISH_EVENT);
evt.finishList=img.sourceArr.length===1 ?img.finishList[0] : img.finishList;
document.dispatchEvent(evt);
}
return true;
}
img.src=img.sourceArr[img.n];
return false;
}