如何使用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預加載 內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!