通过监听load事件实现图片预加载
window.onload=function(){ // 这里的onload属性 可以使里面代码等页面完全加载完在执行
var img=document.querySelector("img"); // 这样并不好 万一图片很多 就需要一直等待
console.log(img.width);
}
第一版
这版只是简单理解以下onload 实际结果是错误的 不能用
init();
function init() {
var arr = [];
for (var i = 2; i < 80; i++) { // 循环是同步的 但速度很快
var img = new Image();
img.src = "./img/" + i + "-.jpg";
img.onload = function () { // onload加载时异步的
arr.push(this); // this是当前加载的图片
if (arr.length >= 78) {
loadFinish(arr); // 没有图片的时候
}
document.body.appendChild(this);
console.log(img) // 在每一张图片加载完成后 img已经被改成了最后一张 所以每次都打印最后一张
}
}
}
function loadFinish(arr) {
arr.forEach(function (item) {
console.log(item.src); // 由于加载是异步的 所以 图片并不是按照想要的顺序被push进数组的 而是谁先加载完 谁就进数组 所以不可以用这种办法哦
})
}
第二版
我们想得到的是 加载完第一张图在加载第二张图 类似下面这样!
var arr = [];
var img = new Image();
img.src = "./img/2-.jpg";
img.onload = function () {
arr.push(this);
var img1 = new Image();
img1.src = "./img/3-.jpg";
img1.onload = function () {
arr.push(this);
var img2 = new Image();
img2.src = "./img/4-.jpg";
img2.onload = function () {
arr.push(this);
var img3 = new Image();
img3.src = "./img/5-.jpg";
img3.onload = function () {
...
}
}
}
}
当然我们不能按照上述办法这么写 😃
下面这个办法 好像可以实现了 但是还不够优雅
var num=2,arr=[]; // 一共放了从2-79这么多张图 所以从2开始
init();
function init(){
var img=new Image();
img.src="./img/"+num+"-.jpg";
img.addEventListener("load",loadHanlder); // 这张图加载完了 进入函数
}
function loadHanlder(e){
arr.push(this); // 将每张图push到数组里
num++; // 修改img的src属性 再次出发监听事件
if(num>79){
loadFinish(arr); // 直到后面没有图片要加载了 跳出函数
return;
}
var img=new Image();
img.src="./img/"+num+"-.jpg"; // 这里的img变量会被不停的修改src
img.addEventListener("load",loadHanlder) // 再进来这个函数
img.addEventListener("error",errorHanlder);
}
function errorHanlder(e){
console.log(e);
}
function loadFinish(arr){
arr.forEach(function(item){
console.log(item.src);
})
}
第三版
根据事件中的this指向 减少代码冗余
var num=2,arr=[]
init();
function init(){
var img=new Image();
img.addEventListener("load",loadHandler);
img.src="./img/"+num+"-.jpg";
}
function loadHandler(e){
// 把当时加载图片复制一份放在数组中,这个复制的图片就是当时这个地址的图片
arr.push(this.cloneNode(false));
num++;
if(num>79){
this.removeEventListener("load",loadHandler);
loadFinish(arr);
return;
}
this.src="./img/"+num+"-.jpg"; // 事件的回调函数中 this指向被监听的元素 所以这里的this就是init函数中的img 可以直接修改img的src 让他再次进入loadHander函数!
}
function loadFinish(arr){
arr.forEach(function(item){
console.log(item.src);
})
}
第四版
把上面的封装出来
var yee=(function(){
return{
loadImage:function(arr,callback,basePath){ // 三个参数 图片名的数组 回调函数 相同的路径
if(typeof basePath==="string"){
arr=arr.map(function(item){
return basePath+item;
})
}
var img=new Image(); // 这是一个图片 图片的src改变 会重新加载 执行loadHandler函数
img.addEventListener("load",this.loadHandler); // 这里的this是yee这个对象
img.addEventListener("error",this.loadHandler)
img.resultArr=[];
img.num=0; // arr的索引
img.arr=arr; // 要在监听的回调函数中取到arr 所以存在img属性上
img.self=this; // 低耦合
img.callback=callback;
img.src=arr[0]; // 第一次的src是第一张图
},
loadHandler:function(e){
if(e.type!=="error") this.resultArr.push(this.cloneNode(false)); // 如果没有错误 将每一个img的复制品push到数组里
this.num++; // 改变地址 准备执行下一次
if(this.num>this.arr.length-1){ // 如果到了数组的最后一项
this.removeEventListener("load",this.self.loadHandler); // 这里的this是img 侦听里的回调函数的this指向被侦听的元素 如果想要在这里移除侦听 需要保存上面的this 也就是yee对象
if(this.callback){ // 如果存在callback函数
this.callback(this.resultArr.slice()); // 复制一个最终数组
}else{
var evt=new Event("Load_image_Finish"); // 如果没有callback函数 用自定义事件的属性抛发出去
evt.resultArr=this.resultArr; // 事件添加resultArr属性 携带最终的数组(这里为什么不用复制?)
document.dispatchEvent(evt);// 抛发出事件 被侦听的地方会收到
}
this.resultArr=null;
this.self=null;
this.callback=null;
this.arr=null;
return;
}
this.src=this.arr[this.num]; // 按照arr里的顺序 修改这个图片的src属性 img的src属性被修改 将触发监听 回到上面的函数
}
}
})()