最近在使用vue動(dòng)態(tài)設(shè)置圖片路徑的時(shí)候遇到了一些問(wèn)題,特此整理。
我想實(shí)現(xiàn)的效果:點(diǎn)擊圖片,彈出系統(tǒng)圖片選擇框乳蛾,選擇圖片后替換原圖片。
App.vue中:
<input type="file" id="avatar" @change="chooseFile($event)" accept="image/*" style="display: none" >
<label for="avatar">
<img :src="../assets/user_1.png" alt="圖片">
</label>
結(jié)果:
默認(rèn)圖片加載成功峦萎,點(diǎn)擊該圖片可以彈出圖片選擇框屡久。
本著組件抽象的原則,我想把上述代碼抽象成組件爱榔,并且希望默認(rèn)的圖片url可以在父組件指定被环,于是,我這樣寫:
App.vue:
<template>
<ItemShow-imageChoose id="userPicture" imageSrc="../assets/user.png"></ItemShow-imageChoose>
</template>
<script>
import ItemShow_imageChoose from "./components/ItemShow-imageChoose"
export default {
name:'App',
components: {
"ItemShow-imageChoose":ItemShow_imageChoose
}
}
./components/ItemShow-imageChoose.vue:
<template>
<div>
<input type="file" :id="id" @change="chooseFile($event)" accept="image/*" style="display: none" >
<label :for="id">
<img :src="imageSrc" alt="圖片">
</label>
</div>
</template>
<script>
export default{
name:'ItemShow_imageChoose',
props:{
"id":[String],
"imageSrc":[String]
},
methods:{
chooseFile(e){
// this.$emit('choose',e.target.files)
}
}
}
</script>
結(jié)果:默認(rèn)圖片沒有加載出來(lái)详幽。
開始一步步找錯(cuò)....
首先筛欢,把圖片的src移至子組件的data中浸锨,看圖片是否能加載出來(lái):
./components/ItemShow-imageChoose.vue:
<template>
<div>
<input type="file" :id="id" @change="chooseFile($event)" accept="image/*" style="display: none" >
<label :for="id">
<img :src="src" alt="圖片" />
</label>
</div>
</template>
<script>
export default{
name:'ItemShow_imageChoose',
props:{
"id":[String],
"imageSrc":[String]
},
data(){
return {
src:'../assets/user.png' //重點(diǎn)看這里
}
},
methods:{
chooseFile(e){
// this.$emit('choose',e.target.files)
}
}
}
</script>
結(jié)果:本來(lái)以為這樣寫肯定是對(duì)的,結(jié)果竟然不對(duì)版姑,但是這個(gè)結(jié)果也說(shuō)明:?jiǎn)栴}不是出在父子組件的參數(shù)傳遞上柱搜。
于是開始查資料....
看了一些文章和問(wèn)答,也大致理解了出錯(cuò)的原因(參考文章見附錄)剥险,是圖片路徑的問(wèn)題聪蘸。
如果圖片地址是直接寫死在html或者css里的,webpack會(huì)幫你處理這個(gè)圖片最終的地址(要用到url-loader)表制,例如:
初始:
<template>
<img src="./相對(duì)地址.jpg" />
</template>
webpack編譯后會(huì)變成:
<img src="/絕對(duì)地址.jpg" />
<!-- 或者 -->
<img src="data:image/jpg;base64......." />
實(shí)測(cè):
<template>
<img src="../assets/user.png" />
</template>
打包成絕對(duì)路徑:以上就是webpack打包的兩種方式健爬,我們重點(diǎn)看第一種。第一種方式么介,圖片是以絕對(duì)路徑(以/
開頭的路徑就是絕對(duì)路徑娜遵,/
指根目錄,根目錄在本地就是指磁盤壤短,在github上就是指?jìng)}庫(kù)的根目錄设拟,在網(wǎng)站上就是指服務(wù)器的根目錄)進(jìn)行查找,圖片的目錄為/static/img久脯,但是我們查看上圖項(xiàng)目目錄纳胧,發(fā)現(xiàn)static目錄下并沒有img目錄,也沒有圖片帘撰,那么這里的路徑是怎么來(lái)的呢躲雅?
運(yùn)行npm run build,再看一下項(xiàng)目目錄:
我們?cè)赿ist目錄下面找到了該圖片骡和。由此知道,webpack打包后相寇,會(huì)將靜態(tài)資源文件放在dist/static/img下慰于,我們的網(wǎng)站實(shí)際上以dist目錄作為根目錄,并由此加載該目錄下的index.html所需的css唤衫、js婆赠、img等。
現(xiàn)在我們使用Vue.js來(lái)動(dòng)態(tài)定義圖片路徑:
<template>
<div>
<img :src="src" alt="圖片" />
</div>
</template>
<script>
export default{
data(){
return {
src:`../assets/user.png`
}
}
}
</script>
結(jié)果:dist目錄為根目錄,index.html的路徑為“./index.html”佳励,那“../assets/user.png”即為與dist目錄平級(jí)的assets目錄下面的user.png休里,我們發(fā)現(xiàn)該目錄不存在,圖片自然加載失敗赃承。
當(dāng)Vue.js來(lái)動(dòng)態(tài)定義圖片路徑的時(shí)候妙黍,url-loader是無(wú)法探測(cè)到圖片路徑的。我們build后發(fā)現(xiàn)瞧剖,圖片根本不會(huì)打包輸出到dist目錄(webpack是按需打包的):
由上圖可知拭嫁,dist目錄下無(wú)圖片文件或文件夾可免。
如何解決?
我整理并測(cè)試了以下三種解決辦法:
1做粤、絕對(duì)路徑訪問(wèn)
把圖片放到靜態(tài)資源目錄static目錄下(build 會(huì)將static目錄中的文件或者文件夾按照原本的結(jié)構(gòu)放在dist目錄下)浇借,并用/static絕對(duì)路徑訪問(wèn):
<template>
<div>
<img :src="src" alt="圖片" />
</div>
</template>
<script>
export default{
data(){
return {
src:`/static/img/user.png`
}
}
}
</script>
結(jié)果:2、使用require
如果想在不調(diào)整目錄結(jié)構(gòu)的情況下讀取圖片怕品,還可以使用require:
data(){
return {
src:require('../assets/user.png') //重點(diǎn)看這里
}
}
該結(jié)果與上面說(shuō)的webpack打包的第一種方式結(jié)果相同妇垢。
缺點(diǎn):由于CommonJS只允許使用字符串字面量,所以不利于組件化肉康,靈活性較差闯估。
3、使用import
也可以用import引入圖片路徑:
<template>
<div>
<img :src="src" alt="圖片" />
</div>
</template>
<script>
import userPath from '../assets/user.png'
export default{
data(){
return {
src:userPath
}
}
}
</script>
結(jié)果:該結(jié)果與上面說(shuō)的webpack打包的第一種方式結(jié)果相同迎罗。
這篇博客就先整理到這里睬愤。多花些時(shí)間踩踩坑也是很好的,學(xué)到了就是賺到了纹安。由于個(gè)人水平有限尤辱,博客錯(cuò)誤之處,煩請(qǐng)指正厢岂!
附完整代碼
./components/ItemShow-imageChoose.vue:
<template>
<div>
<input type="file" :id="id" @change="chooseFile($event)" accept="image/*" style="display: none" >
<label :for="id">
<img :src="'/static/img/'+imageSrc" alt="圖片" />
</label>
</div>
</template>
<script>
export default{
name:'ItemShow_imageChoose',
props:{
"id":[String],
"imageSrc":[String]
},
methods:{
chooseFile(e){
var currentImg=e.target.nextElementSibling.childNodes[0]
currentImg.setAttribute('src',window.URL.createObjectURL(e.target.files[0]))
currentImg.onload=function () {
window.URL.revokeObjectURL(this.src)
}
}
}
}
</script>
參考:
1光督、Vue中img的src屬性綁定與static文件夾
2、問(wèn):vue+webpack動(dòng)態(tài)設(shè)置圖片src導(dǎo)致404錯(cuò)誤