
前言
花里胡哨度[注1]要求越高的页面,用到的图片、音频什么的就越多,比如什么结婚请柬、展会请柬、发布会宣传页、数据大屏。虽然现在浏览器不允许网页在没有用户交互的情况下播放音频,但是,我们依旧要在页面展现的同时,准备好所有的静态资源。
丑陋的预加载
预加载即提前加载,浏览器在请求一张图片时,会缓存到本地,在下次请求同样的地址时,会直接在本地缓存读取(304),在本地读取的时间基本可以忽略不计。如果我们能够在图片未加载完成时给用户一个加载进度,提示用户:“急什么,马上完事!”,则能够有效的提升用户体验。
单张预加载
let img = new Image(
img.src = "@/../../xx.png"
img.onload = ( => {
//...
}
这是为大家所熟知的预加载方式,但是这种方法只适用于单张图片的预加载。
多张预加载
很简单,我们给图片们定义一个数组就好了
let imagesPathArr = ["@/../../xx.png","@/../../yy.png","..."];
然后我们再用循环去加载这些图片
let count = 0
for (let item of imagesPathArr {
let img = new Image(
img.src = item
img.onload = ( => {
count++
if (count === imagesPathArr.length {
// ... 加载完成
}
}
}
我们甚至可以通过count/imagesPathArr.length算出加载的百分比 。
同学说:“我可以把图片从0-99命名,加载时只需要循环一百次就可以了!”
那么我们的代码就长这样:
for(let i = 0;i<=99;i++{
let img = new Image(
img.src = `@/../../${i}.png`
img.onload = ( => {
count++
if (count === imagesPathArr.length {
// ... 加载完成
}
}
}
ok,看起来没有任何问题,实际上也没有任何问题。
那么有没有一种方式,优雅的预加载呢?有。
优雅的预加载
- 第一,我们无需知道加载的图片有多少;
- 第二,我们无需知道加载的图片叫什么;
- 第三,我们无需知道图片的格式是什么。
他🐎的,这听起来就优雅,相当于什么都不用干,就把预加载做出来了!
本期的主角登场
require.context
好像这个api已经存在了好久了,但是我是最近才知道的😅,在这里分享给还没用过的同学。
let requireModule = require.context(
"../../../public/static/img", // 需要遍历的路径
false, // 是否递归,设置为true会递归到最后一级文件夹
/\.png|\.webp|\.jpg|\.jpeg|\.bmp|\.gif$/ //匹配的正则表达式
;
上述代码匹配了常用的图片格式。
./xxx.png的项,所以,只要去掉./就得到了文件夹下所有的图片。
let imagesPathArr = [];
for (var i = 0; i < requireModule.keys(.length; i++ {
imagesPathArr.push("/static/img/" + requireModule.keys([i].substr(2, requireModule.keys([i].length;
}
这样,imagesPathArr就拥有了我们指定文件夹下所有的图片路径了,我们根本无需关心图片有多少、叫什么、什么格式。
let count = 0
for (let item of imagesPathArr {
let img = new Image(
img.src = item
img.onload = ( => {
count++
if (count === imagesPathArr.length {
// 加载完成
}
}
}
最后,我们把所有的逻辑封装成一个函数,并给他套上promise
async loadImgs( {
await new Promise((resolve, reject => {
this.$store.dispatch('loadingStart', {
text: "正在加载资源"
}
let requireModule = require.context(
"../../../public/static/img",
false,
/\.png|\.webp|\.jpg|\.jpeg|\.bmp|\.gif$/
;
let imagesPathArr = [];
for (var i = 0; i < requireModule.keys(.length; i++ {
imagesPathArr.push("/static/img/" + requireModule.keys([i].substr(2, requireModule.keys([i].length;
}
let count = 0
for (let item of imagesPathArr {
let img = new Image(
img.src = item
img.onload = ( => {
count++
if (count === imagesPathArr.length {
this.$store.dispatch('loadingDone'
resolve(
}
}
}
}
},
我们只需在合适的时机,调用该函数,即可全自动的预加载图片了,而且日后往文件夹内新增或者删除图片,都不用管这一段逻辑,它依然可以稳健运行!如果你有加载音频的需求,也是同理,在正则部分加一个.mp3什么的,使用audio.onload即可!