詳解vue中靜態資源的路徑問題(深度好文)
前言: webpack中的require解析
首先明確一點,在專案中的webpack.config.js等專案配置檔案中使用的require屬於nodejs範疇,而進入index.js後,載入的元件中的require都屬於webpack的解析範疇。
webpack中require的用法:
let url = "@/assets/images/carousel/logo.svg" require(url) //報錯 let url = "logo.svg" require("@/assets/images/carousel/"+url); //正確
這是因為你修改頁面後,webpack進行編譯,等待編譯完,需要進行工程的打包,然後打包正確,才能熱載入執行並重新整理頁面。
如果require中傳入的是個變數,它有可能是計算機系統中的任何目錄下的任何檔案,那麼在打包靜態資源時它有可能會將你的電腦整個磁碟遍歷一遍(它很傻)。所以至少需要給出在哪個路徑下,這樣才能精確的將那個路徑下的對應檔案打包,然後在程式碼執行時,直接用對應檔名生成正則匹配(因為打包後的檔案,可能有hash值。不能直接查檔名),找到後,載入到程式碼中。
所以,請記住儘可能詳細的指定require中的路徑,然後拼接變數.
接下來說下打包後的路徑問題:
webpack將專案中的靜態資源編譯打包後,生成的路徑已經不是原來的那個路徑了。如
src/assets/image/logo.jpg
編譯後可能變成
dist/public/image/logo.1d997ea3.jpg
而通過require("src/assets/image/logo.jpg"),會自動找到並載入dist/public/image/logo.1d997ea3.jpg檔案
一、<template>部分的路徑處理
Vue Loader 在編譯單檔案元件中的 <template> 塊時,它也會將所有遇到的資源 URL 轉換為 webpack 模組請求。(這樣我們就沒必要手動呼叫require了,而是交給vue-loader處理了)
vue-loader預設可以處理的標籤/特性的組合如下:
{ video: ['src', 'poster'], img: 'src', //即img元素上的src屬性 source: 'src', //source元素上的src屬性 image: 'xlink:href' }
面對上面的標籤組合,vue-loader會自動進行資源url的轉換。
轉換規則:
a、如果路徑是絕對路徑,會被原樣保留。如/src/assets/image/login/title.png
//程式碼 <template> <img src="/src/assets/image/login/title.png"alt=""> </template> //渲染後html頁面 <img data-v-70c98a68="" src="/src/assets/image/login/title.png" alt=""> //當然這個圖片是無法展示的,因為編譯後title.png已不在src/assets/image/login下了
b、如果路徑以 . 開頭,將會被看作相對的模組依賴。如 ./titlea.png
//程式碼 <img src="./titlea.png" alt=""> //渲染後html頁面 <img data-v-70c98a68="" src="/static/img/titlea.1e9fa570.png" alt="">
c、如果路徑以 @ 開頭,也會被看作模組依賴。如果你的 webpack 配置中給 @ 配置了 alias,這就很有用了。所有 vue-cli 建立的專案都預設配置了將 @ 指向 /src
//程式碼 <img src="@/assets/image/login/title.png" alt=""> //渲染後html頁面 <img data-v-70c98a68="" src="/static/img/title.1e9fa570.png" alt="">
d、如果路徑以 ~ 開頭,其後的部分將會被看作模組依賴,既可以載入含有別名的靜態資源,又可以載入node-modules中的資源。如
//程式碼 <img src="~@/assets/image/login/title.png" alt=""> //渲染後html頁面 <img data-v-70c98a68="" src="/static/img/title.1e9fa570.png" alt=""> //程式碼 <img src="~[npm包名]/xxx/logo.png" alt=""> //渲染後的html頁面 <img data-v-70c98a68="" src="/static/img/logo.2f53e458.png" alt="">
二、<style>部分的路徑處理
由於vue-loader在處理style時,採用的是style-loader,所以可能 和上面<template>部分的轉換規則不太一樣。
在vue-loader的內部使用瞭如下的配置(不一定配置,也有可能通過js直接給rules賦值):
//在vue-loader的內部使用css-loader module.exports = { module: { rules: [ { test: /\.css$/, loader: 'css-loader', options: { url: true, //預設選項 }, }, ], }, };
url為true時,則意味著可以將url中的字串通過require()載入進來。
轉換規則
a、如果路徑是絕對路徑,會被原樣保留。如/src/assets/image/login/title.png
//程式碼 <style scoped> .login-wrap { background-image: url("/src/assets/image/login/title.png"); } </style> //渲染後css .login-wrap[data-v-70c98a68] { background-image: url(/src/assets/image/login/title.png); }
同樣這個圖片是無法展示的,因為編譯後title.png已不在src/assets/image/login下了。
b、如果路徑以 . 開頭,將會被看作相對的模組依賴。如 ./titlea.png
//程式碼 <style scoped> .login-wrap { background-image: url("./titlea.png"); } </style> //渲染後css .login-wrap[data-v-70c98a68] { background-image: url(/static/img/titlea.1e9fa570.png); }
c、如果路徑以 ~ 開頭,其後的部分將會被看作模組依賴,即可以載入含有別名的靜態資源,又可以載入node-modules中的資源。如
//程式碼 <style scoped> .login-wrap { background-image: url("~[npm包名]/logo.png"); } </style> //渲染後css .login-wrap[data-v-70c98a68] { background-image: url(/static/img/logo.e05643fc.png); } //程式碼 <style scoped> .login-wrap { background-image: url("~@/assets/image/login/bg.png"); } </style> //渲染後css .login-wrap[data-v-70c98a68] { background-image: url(/static/img/bg.1d997ea3.png); }
注意:和上面的<template>相比,唯獨少了直接用@開頭的方式url("@/assett/logo.png"),所以下面寫法是錯誤的
//程式碼 <style scoped> .login-wrap { background-image: url("@/assets/image/login/bg.png"); } </style>