前言

在前端开发中,对页面花里胡哨度[注1]要求越高的页面,用到的图片、音频什么的就越多,比如什么结婚请柬、展会请柬、发布会宣传页、数据大屏。虽然现在浏览器不允许网页在没有用户交互的情况下播放音频,但是,我们依旧要在页面展现的同时,准备好所有的静态资源。

注1:花里胡哨度(garish degree),又名难做指数,江湖人称领导开心点

丑陋的预加载

预加载即提前加载,浏览器在请求一张图片时,会缓存到本地,在下次请求同样的地址时,会直接在本地缓存读取(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命名,加载时只需要循环一百次就可以了!”

可以,那么假如我们用python写了一个重命名脚本,把这一百张图片从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,看起来没有任何问题,实际上也没有任何问题。

但是在使用过程中,我们会发现,图片的格式不一定是统一的(当然你可以将他们转换成统一的),而且这种方式看起来太丑了,一点也不够优雅。

那么有没有一种方式,优雅的预加载呢?有。

优雅的预加载

要实现优雅的预加载,我们要优哪些方面?

  • 第一,我们无需知道加载的图片有多少;
  • 第二,我们无需知道加载的图片叫什么;
  • 第三,我们无需知道图片的格式是什么。

他的,这听起来就优雅,相当于什么都不用干,就把预加载做出来了!

但是,众所周知,浏览器环境没有直接操作文件系统的能力,我们无法像node一样,直接使用fs,怎么才能做到如上所说的呢?从第一步来看,我们至少要遍历一个父级文件夹吧?

本期的主角登场

require.context

它是一个webpack的api,可以通过这个方法获取一个特定的上下文,用来实现文件的批量自动化导入,如果你使用vite,那么可以使用 import.meta.globEager(),本文只用require.context举例。

好像这个api已经存在了好久了,但是我是最近才知道的,在这里分享给还没用过的同学。

使用语法如下:

        let requireModule = require.context(
"../../../public/static/img", // 需要遍历的路径
false, // 是否递归,设置为true会递归到最后一级文件夹
/\.png|\.webp|\.jpg|\.jpeg|\.bmp|\.gif$/ //匹配的正则表达式
);

上述代码匹配了常用的图片格式。

如果我们循环它的key(),会得到类似./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就拥有了我们指定文件夹下所有的图片路径了,我们根本无需关心图片有多少、叫什么、什么格式。

下面直接对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即可!

使用require.context实现优雅的预加载的更多相关文章

  1. iOS教程:如何使用Core Data – 预加载和引入数据

    这是接着上一次<iOS教程:Core Data数据持久性存储基础教程>的后续教程,程序也会使用上一次制作完成的. 再上一个教程中,我们只做了一个数据模型,之后我们使用这个数据模型中的数据创 ...

  2. Javascript图片预加载详解

    预加载图片是提高用户体验的一个很好方法.图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度.这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速.无缝地发布 ...

  3. ASP.NET MVC3 Razor 调试与预加载

    目录(?)[-] 获取服务器信息 FormsAuthenticationSlidingExpiration 属性 MVC3预加载   在ASP.NET MVC3开发中,调试中怎么也是不可缺少的,那对于 ...

  4. entity framework 数据加载三种方式的异同(延迟加载,预加载,显示加载)

    三种加载方式的区别 显示加载: 显示加载

  5. Entity Framework关联查询以及数据加载(延迟加载,预加载)

    数据加载分为延迟加载和预加载 EF的关联实体加载有三种方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy Loading和Explicit Lo ...

  6. Angular.JS + Require.JS + angular-async-loader 来实现异步加载 angular 模块

    传统的 angular 应用不支持异步加载模块,必须在 module 启动的时候,所有模块必须预加载进来. 通过使用 angular-async-loader 库,我们可以使用 requirejs 等 ...

  7. ViewPager的刷新、限制预加载、缓存所有

    [框架]: 公共部分:左侧菜单.TitleBar.RadioGroup(3个RadioButton:X.Y.Z) 选择X页面:指示器+ViewPager [要达成的效果]: (1)左侧选择A,进入X页 ...

  8. 关于禁止ViewPager预加载问题【转】

    转自:http://blog.csdn.net/qq_21898059/article/details/51453938#comments 我最近上班又遇到一个小难题了,就是如题所述:ViewPage ...

  9. ViewPager防止Fragment销毁以及取消Fragment的预加载

    存在的问题 1. 默认情况下,ViewPager会根据setOffscreenPageLimit()方法设置的大小,自动预加载2. 还是根据setOffscreenPageLimit()方法设置的大小 ...

  10. 基于spring的web项目启动时预加载数据到ServletContext

    1.要在web启动时预加载数据到ServletContext,实现方法有很多,一种比较简单的方案就是: 1)新建一个bean,定义其初始化方法: <bean id="beanId&qu ...

随机推荐

  1. 快速排序(Java分治法)

    快速排序(Java分治法) 文章目录 快速排序(Java分治法) 0. 分治策略 1.思路步骤 2.代码 3.复杂度分析 3.1 最好情况 3.2 最坏情况 3.3 平均情况 3.4 性能影响因素 4 ...

  2. 让VMWARE ESXI 虚拟机开机进入BIOS设置

    VMware vSphere Client 里面选中需要从光驱启动的客户机,单击右键选择 "编辑设置", 在虚拟机属性的窗口里面选择 "选项 "选项卡 ,单击& ...

  3. nginx配置权重,ip_hash....

    nginx为后端web服务器(apache,nginx,tomcat,weblogic)等做反向代理 几台后端web服务器需要考虑文件共享,数据库共享,session共享问题.文件共享可以使用nfs, ...

  4. 搬运 nginx代理https

    oauth2-client在Nginx代理后遇到的问题和解决方案  2020-01-17 2020-05-27  TECH 30 MINUTES READ (ABOUT 4442 WORDS) OAu ...

  5. Go_day06

    Go基础语法 错误和异常 什么是错误error 错误是指可鞥出现问题的地方出现了问题,这种情况在预料之中 func main() { //打开一个文件 file, err := os.Open(&qu ...

  6. sql 查询大数据 常用 50列优化

    大数据量的问题是很多面试笔试中经常出现的问题,比如baidu google 腾讯 这样的一些涉及到海量数据的公司经常会问到. 下面的方法是我对海量数据的处理方法进行了一个一般性的总结,当然这些方法可能 ...

  7. Kakao Brain 的开源 ViT、ALIGN 和 COYO 文字-图片数据集

    最近 Kakao Brain 在 Hugging Face 发布了一个全新的开源图像文本数据集 COYO,包含 7 亿对图像和文本,并训练了两个新的视觉语言模型 ViT 和 ALIGN ViT 和 A ...

  8. Ocelot的限流、熔断和负载均衡

    一.限流 想要在Ocelot中设置限流,需要在设置如下绿色所示: { "GlobalConfiguration": { "RateLimitOptions": ...

  9. Kafka 管理【主题、分区、消费者组】

    更多内容,前往 IT-BLOG 主题操作 使用 kafka-topics.sh 工具可以执行主题的大部分操作.可以用它创建.修改.删除和查看集群里的主题.要使用该工具的全部功能,需要通过 --zook ...

  10. 使用 baget 搭建 nuget 私有服务

    现在几乎所有语言都提供包管理工具,比如 JavaScript 的 npm ,Java 的 Maven ,Dart 的 pub ..Net 程序当然是 NuGet .NuGet 也出现很多年了,奇怪的是 ...