先看一下產(chǎn)品需求,如下圖所示,
產(chǎn)品要求圖片和它的名稱一一對應(yīng),本來是非常簡單的需求,后臺直接返回圖片路徑和名稱,前臺直接讀取就可以了,但是我們沒有存儲圖片的服務(wù)器,再加上是一個實(shí)驗性的需求,圖片需要存放到前臺。當(dāng)時我想,vue 中的img 的src 可以動態(tài)綁定到一個變量上, 很簡單嗎,就沒有考慮太多,直接開始做了。
首先和后臺商量一下數(shù)據(jù)結(jié)構(gòu),因為圖片要和名稱一一對應(yīng),所以后臺要返回中英文的名稱的映射,我把前臺的圖片名稱直接設(shè)置給后臺給的英文名稱,從而讀取圖片,圖片和中文名稱就一一對應(yīng)了。數(shù)據(jù)結(jié)構(gòu)如下:映射關(guān)系用對象表示,多個圖片,所以放到一個數(shù)組中
[ { CnName:'荷花', EnName: 'lotus' }, { CnName:'康乃馨', EnName: 'carnations' }, { CnName:'牡丹', EnName: 'peony' } ]
現(xiàn)在前臺用vue-cli, 后臺用express 來模擬一下當(dāng)時的開發(fā)場景,也可以還原一下錯誤和業(yè)務(wù)的迭代過程。新建一個文件夾,就叫vue-img吧,然后再在該文件夾中新建兩個文件夾,client, server, client 表示客戶端代碼,server 表示服務(wù)端代碼。 在client 文件夾中,打開命令窗口,執(zhí)行 vue init webpack-simple . 命令,后面的點(diǎn)表示當(dāng)前文件夾,為了簡單,這里使用了simple 模版. server 文件夾,打開命令窗口,先執(zhí)行npm init 初始化為node 項目,然后npm install express cors --save, 安裝依賴,cors 是解決跨域的。
先來寫前端代碼,把a(bǔ)pp.vue 中的template和script中的內(nèi)容清空,保留它的css 樣式內(nèi)容,我們就不用寫樣式了。前端頁面,有兩個部分,一個是button, 點(diǎn)擊按鈕來發(fā)送請求,一個是圖片展示區(qū)域,它用的就是v-for 循環(huán), template 內(nèi)容如下
<div id="app"> <button @click='getFlower'>點(diǎn)擊加載請求</button> <!-- 由于當(dāng)時想當(dāng)然地以為,src 就是綁定一個變量,所以就設(shè)置了一個默認(rèn)變量,這是出錯的過程 --> <ul> <li v-for ="item in flowers" :key="item"> <img :src="defaultImg" alt="flowers"> <p>{{item}}</p> </li> </ul> </div> </template>
由于template中用到了方法 getFlower, 變量defaultImg 和 flowers, 所以要在script中進(jìn)行聲明。defaultImg 是一個圖片,所以還要引入進(jìn)來, 在src 目錄中新建一個img文件夾,放幾張圖片。flowers是一個數(shù)組,我先預(yù)寫了一個['荷花', '康乃馨'],getFlower,因為沒有后臺,所以先沒有寫, 注意如果數(shù)據(jù)量大的,交互復(fù)雜,是要寫mock 數(shù)據(jù)的,這里比較簡單就沒有寫。這也是出錯的原因。代碼如下
import defaultImg from './img/lotus.jpg'; // import 引入圖片 export default { data() { return { flowers: ['荷花', '康乃馨'], defaultImg: defaultImg }; }, methods: { getFlower() {} } };
整個頁面顯示如下,我以為沒有問題了。
現(xiàn)在再來寫后臺代碼, 用express 寫一個后臺接口,還是非常簡單的。在server 文件夾中,建一個文件server.js 來寫后臺代碼
var express = require('express'); var cors = require('cors'); // 引入cors 中間件,解決跨域 var app = express(); app.use(cors()); // 前端發(fā)送的是get請求,接口是flowers. 返回的數(shù)據(jù)code 表示成功或失敗,obj 表示數(shù)據(jù) // 數(shù)據(jù)中Cn 表示中文名稱,En表示中文名稱 app.get('/flowers', (req, res) => { res.json({ code: 0, obj: [ { CnName:'荷花', EnName: 'lotus' }, { CnName:'康乃馨', EnName: 'carnations' }, { CnName:'牡丹', EnName: 'peony' } ] }) }) app.listen(3000, () => { console.log('server start at 3000'); })
現(xiàn)在用nodemon server.js 啟動服務(wù),在瀏覽器地址輸入http://localhost:3000/flowers, 可以看到返回的數(shù)據(jù)表示接口ok.
現(xiàn)在再重新寫一下前端代碼,進(jìn)行前后端聯(lián)調(diào)。由于要發(fā)送請求,還要安裝axios 依賴。首先要根據(jù)后臺接口改一下template 內(nèi)容的li
<ul> <li v-for ="item in flowers" :key="item.EnName"> <img :src="item.EnName" alt="flowers"> <p>{{item.CnName}}</p> </li> </ul>
然后,在script中引入 axios, flowers 數(shù)組清空,default img 刪除 , 引入后臺數(shù)據(jù)所需要的三張圖片, 同時getFlower 方法發(fā)送請求
// 引入axios,用于發(fā)送請求,defaults 設(shè)置后臺請求地址 import axios from 'axios'; axios.defaults.baseURL = "http://localhost:3000" // 引入相關(guān)的圖片, 命名要和后臺保持一致 import lotus from './img/lotus.jpg'; import carnations from './img/carnations.jpg'; import peony from './img/peony.jpg'; export default { data() { return { flowers: [], lotus, carnations, peony }; }, methods: { getFlower() { axios.get('/flowers') .then(res => { if(res.status === 200 && res.data.code === 0) { this.flowers = res.data.obj; } }) } } };
我以為成功了,點(diǎn)擊按鈕發(fā)送請求,但是看到的如下畫面,沒有圖片
當(dāng)時想不通,img 的src 綁定的是變量,它和defaultImg 不應(yīng)該是一樣嗎?打開瀏覽器控制臺,看到如下內(nèi)容,img 的src 已經(jīng)是一個字符串,它不是我們想要的變量了。
我想這里可能是它對item.EnName進(jìn)行了一次解析變成了字符串,就完事了,綁定變量,就是解析一次。而對于defalutImg 來說,它本來就是變量,無法再進(jìn)行分割解析,所以它會去data 里面去找,如果找不到,才報錯。
那么我們現(xiàn)在要做的就是把item.EnName 變成圖片的地址,這樣進(jìn)行一次解析的時候,直接去讀取圖片。要怎么做到呢?當(dāng)時 我也不是很清楚,就百度了一下,有人提到了require 方法, require 一個圖片路徑,我想require 什么,以前沒有聽說過require 這個關(guān)鍵字啊。想了一段時間,突然就明白了,require 是一個commonJs 規(guī)范的關(guān)鍵字,當(dāng)我們在寫node 代碼的時候,都是有require 去讀取資源的。在前端js 中,一直使用import,直接忘記了,不知道怎么用了。webpack 把img 當(dāng)做一種資源,所以使用時要先引進(jìn)。引進(jìn)方式有兩種,一種是import , 一種是require, 因為webpack 同時支持ES6 module 和 commonJs 規(guī)范. import 是個語句,只能在js 代碼頂部使用, 而require 不一樣,它是一個表達(dá)式,可以進(jìn)行賦值操作。我們試一下,用require 引入圖片是怎么樣的效果,在 script 標(biāo)簽時,寫下
var img = require('./img/lotus.jpg'); console.log(img);
刷新瀏覽器,在控制臺上可以看到如下輸出
正好是圖片的路徑,也正是我們想要的內(nèi)容,剛才也說了,require是一個表達(dá)式,它可以用到任何js 表達(dá)式能用到的地方。我這時就想,把后臺返回的代碼進(jìn)行重新組裝,EnName 直接是圖片路徑。getFlower 方法修改如下
getFlower() { axios.get('/flowers') .then(res => { if(res.status === 200 && res.data.code === 0) { this.flowers = res.data.obj.map(item => { return { CnName: item.CnName, EnName: require(`./img/${item.EnName}.jpg`) // 利用require 引入圖片,獲得圖片路徑 } }) } }) }
這時刷新瀏覽器,點(diǎn)擊按鈕發(fā)送請求,可以看到圖片了并且一一對應(yīng), 成功了。
這時又一想,既然require 是一個表達(dá)式,在template模版中是直接可以解析js 表達(dá)式,那么直接把img 的src 綁定到require 表達(dá)式就可以了,把getFlower 方法,回退到上一次代碼,然后template 代碼如下
<ul> <li v-for ="item in flowers" :key="item.EnName"> <img :src="require(`./img/${item.EnName}.jpg`)" alt="flowers"> <p>{{item.CnName}}</p> </li> </ul>
同樣也成功了。
最后寫代碼的時候發(fā)現(xiàn),如果讀取的圖片不存在,上面的方法就會報錯,并且沒有辦法處理。這時還要回到j(luò)s 的代碼處理。我又把html代碼回到以前,然后在getFlower方法中進(jìn)行錯誤處理,既然讀取報錯,我們讀取的代碼就放到try中, 如果有報錯,就在catch 看處理,提供一個默認(rèn)圖片,try catch 處理讀取異常。 try catch 的邏輯
try { img = require(`./img/${item.EnName}.jpg`); } catch (err) { img = require('./img/lotus.jpg'); }
整個app.vue
<template> <div id="app"> <button @click='getFlower'>點(diǎn)擊加載請求</button> <ul> <li v-for ="item in flowers" :key="item.EnName"> <img :src="item.EnName" alt="flowers"> <p>{{item.CnName}}</p> </li> </ul> </div> </template> <script> // 引入axios,用于發(fā)送請求,defaults 設(shè)置后臺請求地址 import axios from 'axios'; axios.defaults.baseURL = "http://localhost:3000"; export default { data() { return { flowers: [] }; }, methods: { getFlower() { axios.get('/flowers') .then(res => { if(res.status === 200 && res.data.code === 0) { this.flowers = res.data.obj.map(item => { var img = null; try { img = require(`./img/${item.EnName}.jpg`); } catch (err) { img = require('./img/lotus.jpg'); } return { CnName: item.CnName, EnName: img } }) } }) } } }; </script>
以上這篇解決vue的 v-for 循環(huán)中圖片加載路徑問題就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com