使用require.context实现优雅的预加载
前言
在前端开发中,对页面花里胡哨度[注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实现优雅的预加载的更多相关文章
- iOS教程:如何使用Core Data – 预加载和引入数据
这是接着上一次<iOS教程:Core Data数据持久性存储基础教程>的后续教程,程序也会使用上一次制作完成的. 再上一个教程中,我们只做了一个数据模型,之后我们使用这个数据模型中的数据创 ...
- Javascript图片预加载详解
预加载图片是提高用户体验的一个很好方法.图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度.这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速.无缝地发布 ...
- ASP.NET MVC3 Razor 调试与预加载
目录(?)[-] 获取服务器信息 FormsAuthenticationSlidingExpiration 属性 MVC3预加载 在ASP.NET MVC3开发中,调试中怎么也是不可缺少的,那对于 ...
- entity framework 数据加载三种方式的异同(延迟加载,预加载,显示加载)
三种加载方式的区别 显示加载: 显示加载
- Entity Framework关联查询以及数据加载(延迟加载,预加载)
数据加载分为延迟加载和预加载 EF的关联实体加载有三种方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy Loading和Explicit Lo ...
- Angular.JS + Require.JS + angular-async-loader 来实现异步加载 angular 模块
传统的 angular 应用不支持异步加载模块,必须在 module 启动的时候,所有模块必须预加载进来. 通过使用 angular-async-loader 库,我们可以使用 requirejs 等 ...
- ViewPager的刷新、限制预加载、缓存所有
[框架]: 公共部分:左侧菜单.TitleBar.RadioGroup(3个RadioButton:X.Y.Z) 选择X页面:指示器+ViewPager [要达成的效果]: (1)左侧选择A,进入X页 ...
- 关于禁止ViewPager预加载问题【转】
转自:http://blog.csdn.net/qq_21898059/article/details/51453938#comments 我最近上班又遇到一个小难题了,就是如题所述:ViewPage ...
- ViewPager防止Fragment销毁以及取消Fragment的预加载
存在的问题 1. 默认情况下,ViewPager会根据setOffscreenPageLimit()方法设置的大小,自动预加载2. 还是根据setOffscreenPageLimit()方法设置的大小 ...
- 基于spring的web项目启动时预加载数据到ServletContext
1.要在web启动时预加载数据到ServletContext,实现方法有很多,一种比较简单的方案就是: 1)新建一个bean,定义其初始化方法: <bean id="beanId&qu ...
随机推荐
- Spring bean注入问题:NoUniqueBeanDefinitionException解决方案归纳
引言 spring实现的bean自动注入在项目开发中是一个经常使用到的功能,但自动装配两个或多个bean时,会抛出NoUniqueBeanDefinitionException:No qualifyi ...
- [.Net]Framwork WebAPI添加接口请求监控
思路: 通过重写 ActionFilterAttribute 拦截Action的请求及返回信息,实现对接口请求的监听. 最终效果如下: 全局启用需配置如下: 局部启用需配置如下: 源码如下: 1 // ...
- Java下变量大小写驼峰、大小写下划线、大小写连线转换
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artif ...
- windows下配置JDK教程
1.思路: 首先要确定所要用的应用可以兼容哪个版本jdk,然后开始下载对应的版本,最后安装,配置环境变量,测试,部署完成. 2.jdk下载地址: 如果下载全新的jdk可以直接百度jdk官网下载 如果需 ...
- SSRF Server-Side Request Forgery(服务器端请求伪造)
什么是SSRF? 犹如其名,SSRF(Server-Side Request Forgery)服务端请求伪造,攻击者可以控制服务器返回的页面,借用服务器的权限访问无权限的页面. 这是一个允许恶意用户导 ...
- University of Toronto Faculty of Arts and Science MAT344– Final Assessment Combinatorics Instructors: Stanislav Balchev and Max Klambauer 19 August 2020
目录 随便找的一份测试题 T7 T9 T6 T5 solution to (a) solution to (b) solution to (c) solution to (d) T1 T2 T3 T4 ...
- 使用 zeromq与cppzmq 程序退出遇到的坑
在使用zeromq 退出的时候还遇到一点坑,对于服务deaman(守护进程)化的进程可能会遇到这个问题. 现象: 这个问题导致的现象是服务一旦关闭(stop),就会 core dump,core du ...
- springboot 连接不上 redis 的三种解决方案!
针对于这种情况,首先,我们最简单直接的方法就是需要确认Redis是否已经正常启动(验证方法:如果安装在Linux下的话可以使用ps-ef|grep redis来进行确认是否开启) 如果未开启,我们可以 ...
- Java面试——MyBatis
一.MyBatis 与 JDBC 的区别 [1]JDBC 是 Java 提供操作数据库的 API:MyBatis 是一个持久层 ORM 框架,底层是对 JDBC 的封装.[2]使用 JDBC 需要连接 ...
- 2020寒假学习笔记13------Python基础语法学习(二)
同一运算符 同一运算符用于比较两个对象的存储单元,实际比较的是对象的地址. 运算符 描述 is is 是判断两个标识符是不是引用同一个对象 is not is not 是判断两个标识符是不是引用 ...