相信用過vue的小夥伴,肯定被面試官問過這樣一個問題:在vue中動態的引入圖片為什麼要使用require
有些小夥伴,可能會輕蔑一笑:呵,就這,因為動態新增src被當做靜態資源處理了,沒有進行編譯,所以要加上require, 我倒著都能背出來......
emmm... 乍一看好像說的很有道理啊,但是仔細一看,這句話說的到底是個啥?針對上面的回答,我不禁有如下幾個疑問:
當我產生最後一個疑問的時候,發現上面的答案看似說了些啥,但好像又什麼都沒說...... 如果各位看官老爺也有如上幾個疑問,那就讓我給大家一一解惑
與靜態資源相對應的還有一個動態資源,先讓我們看看網上的各位大佬們怎麼解釋的。
靜態資源:一般使用者端傳送請求到web伺服器,web伺服器從記憶體在取到相應的檔案,返回給使用者端,使用者端解析並渲染顯示出來。
動態資源:一般使用者端請求的動態資源,先將請求交於web容器,web容器連線資料庫,資料庫處理資料之後,將內容交給web伺服器,web伺服器返回給使用者端解析渲染處理。
其實上面的總結已經很清晰了。站在一個vue專案的角度,我們可以簡單的理解為:
靜態資源就是直接存放在專案中的資源,這些資源不需要我們傳送專門的請求進行獲取。比如assets目錄下面的圖片,視訊,音訊,字型檔案,css樣式表等。
動態資源就是需要傳送請求獲取到的資源。比如我們刷淘寶的時候,不同的商品資訊是傳送的專門的請求獲取到的,就可以稱之為動態資源。
回答這個問題之前,我們需要了解一下,瀏覽器是怎麼能執行一個vue專案的。
我們知道瀏覽器開啟一個網頁,實際上執行的是html,css,js三種型別的檔案。當我們本地啟動一個vue專案的時候,實際上是先將vue專案進行打包,打包的過程就是將專案中的一個個vue檔案轉編譯成html,css,js檔案的過程,而後再在瀏覽器上執行的。
那動態新增的src如果我們沒有使用require引入,最終會打包成什麼樣子呢,我帶大家實驗一波。
// vue檔案中動態引入一張圖片
<template>
<div class="home">
<!-- 通過v-bind引入資源的方式就稱之為動態新增 -->
<img :src="'../assets/logo.png'">
可以發現,編譯過後的靜態地址確實是和dist下編譯後圖片地址是一致的,從而驗證我們的想法。
到這裡我們其實就可以解釋上面的問題了:動態新增的src,被編譯過後的靜態路徑為什麼無法正確的引入資源?
因為動態的新增的src編譯過後的地址,與圖片資源編譯過後的資源地址不一致, 導致無法正確的引入資源
編譯過後的src地址:../assets/logo.png
編譯過後的圖片資源地址:/img/logo.6c137b82.png
那要怎麼解決上述的問題呢,答案就是:require
4. 加上require為什麼能正確的引入資源,是因為加上require就能編譯了?
針對這個問題,首先就要否定後半句,無論加不加require,vue檔案中引入一張圖片都會被編譯。
接著我們再來好好了解一下,require。
4.1 require是什麼: 是一個node方法,用於引入模組,JSON或本地檔案
4.2 呼叫require方法引入一張圖片之後發生了什麼:
在回答這個問題之前,容我先對問題3中的內容進行一定的補充。其實如果真的有小夥伴跟著問題三中的操作進行驗證,估計就要開噴了:為什麼我靜態引入的圖片最終編譯的地址和你的不一樣,是個base64,而且打包之後dist下面也沒有生成新的圖片。大概就是下面這樣的情況。
// vue檔案中靜態的引入一張圖片
<template>
<div class="home">
<!-- 直接引入圖片靜態地址, 不再使用v-bind -->
<img src="../assets/logo.png">
上圖就是vue中webpack預設的圖片打包規則。設定 type: 'asset',預設的,對於小於8k的圖片,會將圖片轉成base64 直接插入圖片,不會再在dist目錄生成新圖片。對於大於8k的圖片,會打包進dist目錄,之後將新圖片地址返回給src。
而我在上述測試中使用的圖片,是vue-cli自帶的一張logo圖片,大小是6.69k。按照預設的打包規則,是會轉成base64,嵌入圖片中的。所以為了講述方便,我在vue.config.js中修改了其預設的設定,設定如下:
module.exports = {
// 使用configureWebpack物件,下面可以直接按照webpack中的寫法進行編寫
// 編寫的內容,最終會被webpack-merge外掛合併到webpack.config.js主組態檔中
configureWebpack: {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|webp|avif)(\?.*)?$/,
type: 'asset',
parser: {
dataUrlCondition: {
// 這裡我將預設的大小限制改成6k。
// 當圖片小於6k時候,使用base64引入圖片;大於6k時,打包到dist目錄下再進行引入
maxSize: 1024 * 6
}
}
}
]
}
}
}
那上面說了這麼多,和require有啥關係,自然是有滴。
我們現在知道vue最終是通過webpack打包,並且會在webpack組態檔中編寫一系列打包規則。而webpack中的打包規則,針對的其實是一個一個模組,換而言之webpack只會對模組進行打包。那webpack怎麼將圖片當成一個模組呢,這就要用到我們的正主require。
當我們使用require方法引入一張圖片的時候,webpack會將這張圖片當成一個模組,並根據組態檔中的規則進行打包。我們可以將require當成一個橋樑,使用了require方法引入的資源,該資源就會當成模組並根據組態檔進行打包,並返回最終的打包結果。
回到問題4.2:呼叫require方法引入一張圖片之後發生了什麼
1.如果這張圖片小於專案中設定的資源限制大小,則會返回圖片的base64插入到require方法的呼叫處
2.如果這張圖片大於專案中設定的資源限制大小,則會將這個圖片編譯成一個新的圖片資源。require方法返回新的圖片資源路徑及檔名
回到問題4:為什麼加上require能正確的引入資源
因為通過require方法拿到的檔案地址,是資原始檔編譯過後的檔案地址(dist下生成的檔案或base64檔案),因此可以找對應的檔案,從而成功引入資源。
答案就是這麼簡單,來驗證一波
// vue檔案中使用require動態的引入一張圖片
<template>
<div class="home">
<!-- 使用require動態引入圖片 -->
<img :src="require('../assets/logo.png')">
有問題嗎,沒有問題。到這裡,不妨再對我們的標準答案進行一次優化:
因為動態新增的src,編譯過後的檔案地址和被編譯過後的資原始檔地址不一致,從而無法正確引入資源。而使用require,返回的就是資原始檔被編譯後的檔案地址,從而可以正確的引入資源
看到這,估計還是有一些小夥伴有一些疑問,我再擴充套件一波:
6. 問題3中,靜態的引入一張圖片,沒有使用require,為什麼返回的依然是編譯過後的檔案地址?
答:在webpack編譯的vue檔案的時候,遇見src等屬性會預設的使用require引入資源路徑。參照vue-cli官方的一段原話
當你在 JavaScript、CSS 或 *.vue
檔案中使用相對路徑 (必須以 .
開頭) 參照一個靜態資源時,該資源將會被包含進入 webpack 的依賴圖中。在其編譯過程中,所有諸如 <img src="...">
、background: url(...)
和 CSS @import
的資源 URL 都會被解析為一個模組依賴。
例如,url(./image.png)
會被翻譯為 require('./image.png')
,而:
<img src="./image.png">
將會被編譯到:
h('img', { attrs: { src: require('./image.png') }})
7. 按照問題6中所說,那麼動態新增src的時候也會使用require引入,為什麼src編譯過後的地址,與圖片資源編譯過後的資源地址不一致
答:因為動態引入一張圖片的時候,src後面的屬性值,實際上是一個變數。webpack會根據v-bind指令去解析src後面的屬性值。並不會通過reuqire引入資源路徑。這也是為什麼需要手動的新增require。
8.據說public下面的檔案不會被編譯,那我們使用靜態路徑去引入資源的時候,也會預設的使用require引入嗎?
官方的原文是這樣子的:
任何放置在 public
資料夾的靜態資源都會被簡單的複製,而不經過 webpack。你需要通過絕對路徑來參照它們。
答:不會,使用require引入資源的前提的該資源是webpack解析的模組,而public下的檔案壓根就不會走編譯,也就不會使用到require。
9.為什麼使用public下的資源一定要絕對路徑
答:因為雖然public檔案不會被編譯,但是src下的檔案都會被編譯。由於引入的是public下的資源,不會走require,會直接返回程式碼中的定義的檔案地址,該地址無法在編譯後的檔案目錄(dist目錄)下找到對應的檔案,會導致引入資源失敗。
10.上檔案中提到的webpack,為什麼引入資源的時候要有base64和打包到dist目錄下兩種的方式,全部打包到的dist目錄下,他不香嗎?
答:為了減少http請求。頁面中通過路徑引入的圖片,實際上都會向伺服器傳送一個請求拿到這張圖片。對於資源較小的檔案,設定成base64,既可以減少請求,也不會影響到頁面的載入效能。
以上就是今天的全部內容啦,謝謝各位看官老爺的觀看。不好的地方,還請包涵。不對的地方,還請指正。