如何使用require.context实现优雅的预加载

 更新时间:2023年05月05日 16:51:16   作者:posted  
这篇文章主要介绍了使用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实现优雅的预加载 的文章就介绍到这了,更多相关require.context预加载 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • ES6/JavaScript使用技巧分享

    ES6/JavaScript使用技巧分享

    本篇文章主要给大家讲解了ES6/JavaScript使用技巧,需要的朋友参考一下吧。
    2017-12-12
  • JS检测数组类型的方法小结

    JS检测数组类型的方法小结

    这篇文章主要介绍了js检测数组类型的方法小结,有instanceof方法Array.isArray() 方法和Object.prototype.toString.call()方法,都是比较常用的,需要的朋友可以参考下
    2017-03-03
  • JavaScript闭包实例讲解

    JavaScript闭包实例讲解

    众所周知,JavaScript没有块级作用域,只有函数作用域。那就意味着定义在函数中的参数和变量在函数外部是不可见的,而在一个函数内部任何位置定义的变量,在该函数内部任何地方都可见
    2014-04-04
  • JavaScript引用赋值与传值赋值总结

    JavaScript引用赋值与传值赋值总结

    这篇文章主要介绍了JavaScript引用赋值与传值赋值总结,在JavaScript中基本数据类型都是传值赋值,复合数据类型都是引用赋值(传地址)也叫引用传址,下文更多相关资料,需要的小伙伴可以参考一下
    2022-05-05
  • 微信小程序用户授权弹窗 拒绝时引导用户重新授权实现

    微信小程序用户授权弹窗 拒绝时引导用户重新授权实现

    我们在开发小程序时,如果想获取用户信息,就需要获取用的授权,如果用户误点了拒绝授权,我们怎么样去正确的引导用户重新授权呢。今天就来给大家讲讲如果正确的引导用户授权,需要的朋友可以参考下
    2019-07-07
  • 原生JS实现获取及修改CSS样式的方法

    原生JS实现获取及修改CSS样式的方法

    这篇文章主要介绍了原生JS实现获取及修改CSS样式的方法,结合实例形式简单分析了JavaScript针对页面元素属性动态操作相关实现技巧,需要的朋友可以参考下
    2018-09-09
  • JS高仿抛物线加入购物车特效实现代码

    JS高仿抛物线加入购物车特效实现代码

    本篇文章主要介绍了JS高仿抛物线加入购物车特效实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-02-02
  • js仿搜狐视频记录片列表展示效果

    js仿搜狐视频记录片列表展示效果

    这篇文章主要为大家详细介绍了js仿搜狐视频记录片列表展示效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • JavaScript中async/await的高级用法小结

    JavaScript中async/await的高级用法小结

    JavaScript的异步编程已经从回调(Callback)演进到Promise,再到如今广泛使用的async/await语法,本文为大家整理了7个async/await高级用法,希望对大家有所帮助
    2023-12-12
  • JavaScript中的简写语法分享

    JavaScript中的简写语法分享

    这篇文章主要为大家整理了12个JavaScript中常用的简写语法技巧,文中的示例代码讲解详细,具有一定的参考价值,需要的小伙伴可以收藏一下
    2023-04-04

最新评论