vue3+vite2實現(xiàn)動態(tài)綁定圖片的優(yōu)雅解決方案
背景
在vue3+vite2項目中,我們有時候想要動態(tài)綁定資源,比如像下面的代碼這樣:
<template> <div> <!-- 動態(tài)綁定圖片資源 --> <img :src="img_src"> </div> </template> <script setup> import { ref } from 'vue'; // 靜態(tài)圖片資源 const img_src = ref('./1.jpg'); </script>
實際效果是這樣:
原因分析
我們注意到,控制臺的報錯信息GET http://127.0.0.1:5173/1.jpg 404 (Not Found)
GET
:表示向服務器請求資源的方式。http://127.0.0.1:5173
:表示主機為項目開啟的服務器地址以及端口號http://127.0.0.1:5173/1.jpg
:表示存放在服務器中的圖片資源地址。404 (Not Found)
:狀態(tài)碼,404表示找不到資源。
問題就出在http://127.0.0.1:5173/1.jpg
這里,項目文件的路徑是src/App.vue
,圖片的路徑是src/1.jpg
,因此,圖片在服務器上的存放路徑實際應該是http://127.0.0.1:5173/src/1.jpg
,我們直接在瀏覽器中訪問這個地址。
可以看到,成功獲取了圖片資源。
由于vite打包的機制,造成了路徑錯誤的問題(類似于vue2 + vue-cli項目的動態(tài)綁定圖片問題)。
解決
目前網(wǎng)上的解決方案有很多,這里列出其中一種受眾的,以及筆者在此基礎上進一步加強的解決方案。
普遍的解決方案
話不多說,直接列出代碼:
<template> <div> <!-- 動態(tài)綁定圖片資源 --> <img :src="img_src"> </div> </template> <script setup> import { ref } from 'vue'; // 靜態(tài)圖片資源 const img_src = ref('./1.jpg'); // 主要代碼,利用 new URL().href 進行相對路徑的拼接 function getAssetImage(imgSrc) { return new URL(imgSrc, import.meta.url).href; } // 當然你也可以這樣簡寫,這里用到es6箭頭函數(shù) // const getAssetImage = imgSrc => new URL(imgSrc, import.meta.url).href; </script>
這段代碼的重點是new URL().href
和 es6的 import.meta.url
。
new URL(url, baseUrl).href
:路徑拼接。比如url是./1.jpg
,baseUrl是http://127.0.0.1:5173/src/App.vue
,那么拼接出來就是http://127.0.0.1:5173/src/1.jpg
import.meta.url
:獲取當前模塊的路徑,比如在src/App.vue
中,就是http://127.0.0.1:5173/src/App.vue
。
所以最后的new URL().href
就是真正的圖片資源地址,自己打印一下new URL(url, baseUrl)
和import.meta.url
就容易明白了。
這里給大伙兒畫張圖,便于理解。
優(yōu)雅的解決方案
上面的方案可行,但不夠優(yōu)雅。試想,如果有很多文件都需要動態(tài)綁定靜態(tài)圖片資源,那豈不是每個.vue文件都要封裝一次getAssetImage()
函數(shù)?所以下面介紹一種優(yōu)雅的封裝方案。
封裝的主要問題是如何自動獲取.vue文件的import.meta.url
,就可以不必每次調(diào)用都攜帶import.meta.url
。
核心思路是通過拋出錯誤獲取函數(shù)調(diào)用棧,從而獲得函數(shù)調(diào)用者文件(或者說模塊)的路徑,再通過正則表達式提取出路徑信息,把import.meta.url
替換掉,就能實現(xiàn),只傳圖片相對路徑這一個參數(shù),得到圖片的完整路徑的效果。
直接上代碼:
JavaScript版本
// src/utils/common.js export default { getAssetImage(imgSrc, baseUrl) { // console.log('baseUrl', baseUrl); // console.log('new URL(imgSrc, baseUrl).href', new URL(imgSrc, baseUrl).href); // console.log('import.meta.url', import.meta.url); // console.log('new URL(imgSrc, import.meta.url).href', new URL(imgSrc, import.meta.url).href); // 正則匹配函數(shù)調(diào)用者文件的路徑 const regExp1 = /at Proxy.getAssetImage \((.+)\)/g; // 正則命中目標 let target; try { // 拋出錯誤,獲取函數(shù)調(diào)用棧信息 throw new Error(); } catch (err) { // 匹配函數(shù)調(diào)用者文件的路徑 target = regExp1.exec(err?.stack); // console.log('err.stack', err?.stack); // console.log(target?.[1]); } if (target?.[1]) { // 用戶沒有傳入第二個參數(shù),就使用自動獲取的路徑 baseUrl = baseUrl || target?.[1]; } if (!baseUrl) { // 用戶沒有傳入第二個參數(shù),且獲取函數(shù)調(diào)用者文件的路徑失敗 throw new Error('請傳入第二個參數(shù) import.meta.url'); } // 返回處理后的資源路徑 return new URL(imgSrc, baseUrl).href; } }
TypeScript版本
// src/utils/common.ts export default { getAssetImage(imgSrc: string, baseUrl: string) { // console.log('baseUrl', baseUrl); // console.log('new URL(imgSrc, baseUrl).href', new URL(imgSrc, baseUrl).href); // console.log('import.meta.url', import.meta.url); // console.log('new URL(imgSrc, import.meta.url).href', new URL(imgSrc, import.meta.url).href); // 正則匹配函數(shù)調(diào)用者文件的路徑 const regExp1 = /at Proxy.getAssetImage \((.+)\)/g; // 正則命中目標 let target: RegExpExecArray | null; try { // 拋出錯誤,獲取函數(shù)調(diào)用棧信息 throw new Error(); } catch (err) { // 匹配函數(shù)調(diào)用者文件的路徑 target = regExp1.exec(err?.stack); // console.log('err.stack', err?.stack); // console.log(target?.[1]); } if (target?.[1]) { // 用戶沒有傳入第二個參數(shù),就使用自動獲取的路徑 baseUrl = baseUrl || target?.[1]; } if (!baseUrl) { // 用戶沒有傳入第二個參數(shù),且獲取函數(shù)調(diào)用者文件的路徑失敗 throw new Error('請傳入第二個參數(shù) import.meta.url'); } // 返回處理后的資源路徑 return new URL(imgSrc, baseUrl).href; } }
在.vue文件中使用
// src/App.vue <template> <div> <!-- 測試 --> <img :src="getAssetImage(img_src)"> <!-- 可以試試在嵌套組件中使用^_^ --> </div> </template> <script lang="ts" setup> import { ref } from 'vue'; import common from '@/utils/common.ts'; const img_src = ref('./1.jpg'); // const getAssetImage = img_src => common.getAssetImage(img_src, import.meta.url); // 可以省略第二個參數(shù)import.meta.url,函數(shù)內(nèi)部會自動獲取函數(shù)的調(diào)用路徑。 const getAssetImage = img_src => common.getAssetImage(img_src); // 常規(guī)寫法 // function getAssetImage(img_src) { // return common.getAssetImage(img_src); // } </script>
到此這篇關于vue3+vite2實現(xiàn)動態(tài)綁定圖片的優(yōu)雅解決方案的文章就介紹到這了,更多相關vue3 vite2動態(tài)綁定圖片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue響應式更新機制及不使用框架實現(xiàn)簡單的數(shù)據(jù)雙向綁定問題
vue是一款具有響應式更新機制的框架,既可以實現(xiàn)單向數(shù)據(jù)流也可以實現(xiàn)數(shù)據(jù)的雙向綁定。這篇文章主要介紹了vue響應式更新機制及不使用框架實現(xiàn)簡單的數(shù)據(jù)雙向綁定問題,需要的朋友可以參考下2019-06-06Vue實現(xiàn)在線預覽pdf文件功能(利用pdf.js/iframe/embed)
項目要求需要預覽pdf文件,網(wǎng)上找了很久,發(fā)現(xiàn)pdf.js的效果,這篇文章主要給大家介紹了關于Vue實現(xiàn)在線預覽pdf文件功能,主要利用pdf.js/iframe/embed來實現(xiàn)的,需要的朋友可以參考下2021-06-06Avue自定義formslot調(diào)用rules自定義規(guī)則方式
在Avue框架中,使用formslot自定義表格列時可能會遇到無法調(diào)用Avue的自定義校驗規(guī)則的問題,這通常發(fā)生在嘗試通過formslot自定義設置列的場景中,解決這一問題的一個有效方法是將自定義列與Avue的校驗規(guī)則通過特定方式連接起來2024-10-10vue實現(xiàn)用戶長時間不操作自動退出登錄功能的實現(xiàn)代碼
這篇文章主要介紹了vue實現(xiàn)用戶長時間不操作自動退出登錄功能的實現(xiàn)代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07VUE異步更新DOM - 用$nextTick解決DOM視圖的問題
這篇文章主要介紹了VUE異步更新DOM - 用$nextTick解決DOM視圖的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11