1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > vue的 v-for 循环中图片加载路径问题

vue的 v-for 循环中图片加载路径问题

时间:2024-02-12 23:10:41

相关推荐

vue的 v-for 循环中图片加载路径问题

先看一下产品需求,如下图所示,

产品要求图片和它的名称一一对应,本来是非常简单的需求,后台直接返回图片路径和名称,前台直接读取就可以了,但是我们没有存储图片的服务器,再加上是一个实验性的需求,图片需要存放到前台。当时我想,vue中的img的src可以动态绑定到一个变量上, 很简单吗,就没有考虑太多,直接开始做了。

首先和后台商量一下数据结构,因为图片要和名称一一对应,所以后台要返回中英文的名称的映射,我把前台的图片名称直接设置给后台给的英文名称,从而读取图片,图片和中文名称就一一对应了。数据结构如下:映射关系用对象表示,多个图片,所以放到一个数组中

[{CnName:'荷花',EnName: 'lotus'},{CnName:'康乃馨',EnName: 'carnations'},{CnName:'牡丹',EnName: 'peony'}]

现在前台用vue-cli,后台用express来模拟一下当时的开发场景,也可以还原一下错误和业务的迭代过程。新建一个文件夹,就叫vue-img吧,然后再在该文件夹中新建两个文件夹,client, server, client表示客户端代码,server表示服务端代码。在client文件夹中,打开命令窗口,执行 vue init webpack-simple .命令,后面的点表示当前文件夹,为了简单,这里使用了simple模版. server文件夹,打开命令窗口,先执行npm init初始化为node项目,然后npm install express cors --save,安装依赖,cors是解决跨域的。

先来写前端代码,把app.vue中的template和script中的内容清空,保留它的css样式内容,我们就不用写样式了。前端页面,有两个部分,一个是button,点击按钮来发送请求,一个是图片展示区域,它用的就是v-for 循环, template内容如下

<div id="app"><button @click='getFlower'>点击加载请求</button><!-- 由于当时想当然地以为,src 就是绑定一个变量,所以就设置了一个默认变量,这是出错的过程 --><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中进行声明。defaultImg是一个图片,所以还要引入进来,在src 目录中新建一个img文件夹,放几张图片。flowers是一个数组,我先预写了一个['荷花', '康乃馨'],getFlower,因为没有后台,所以先没有写,注意如果数据量大的,交互复杂,是要写mock数据的,这里比较简单就没有写。这也是出错的原因。代码如下

import defaultImg from './img/lotus.jpg'; // import 引入图片export default {data() {return {flowers: ['荷花', '康乃馨'],defaultImg: defaultImg};},methods: {getFlower() {}}};

整个页面显示如下,我以为没有问题了。

现在再来写后台代码,用express写一个后台接口,还是非常简单的。在server文件夹中,建一个文件server.js来写后台代码

var express = require('express');var cors = require('cors'); // 引入cors 中间件,解决跨域var app = express();app.use(cors());// 前端发送的是get请求,接口是flowers. 返回的数据code 表示成功或失败,obj 表示数据// 数据中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');})

现在用nodemon server.js启动服务,在浏览器地址输入http://localhost:3000/flowers,可以看到返回的数据表示接口ok.

现在再重新写一下前端代码,进行前后端联调。由于要发送请求,还要安装axios 依赖。首先要根据后台接口改一下template内容的li

<ul><li v-for ="item in flowers" :key="item.EnName"><img :src="item.EnName" alt="flowers"><p>{{Name}}</p></li></ul>

然后,在script中引入 axios, flowers数组清空,default img删除 ,引入后台数据所需要的三张图片,同时getFlower方法发送请求

// 引入axios,用于发送请求,defaults 设置后台请求地址import axios from 'axios';axios.defaults.baseURL = "http://localhost:3000"// 引入相关的图片, 命名要和后台保持一致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;}})}}};

我以为成功了,点击按钮发送请求,但是看到的如下画面,没有图片

当时想不通,img的src绑定的是变量,它和defaultImg不应该是一样吗?打开浏览器控制台,看到如下内容,img的src已经是一个字符串,它不是我们想要的变量了。

我想这里可能是它对item.EnName进行了一次解析变成了字符串,就完事了,绑定变量,就是解析一次。而对于defalutImg来说,它本来就是变量,无法再进行分割解析,所以它会去data里面去找,如果找不到,才报错。

那么我们现在要做的就是把item.EnName变成图片的地址,这样进行一次解析的时候,直接去读取图片。要怎么做到呢?当时我也不是很清楚,就百度了一下,有人提到了require方法, require一个图片路径,我想require什么,以前没有听说过require这个关键字啊。想了一段时间,突然就明白了,require是一个commonJs规范的关键字,当我们在写node代码的时候,都是有require去读取资源的。在前端js中,一直使用import,直接忘记了,不知道怎么用了。webpack把img当做一种资源,所以使用时要先引进。引进方式有两种,一种是import ,一种是require,因为webpack同时支持ES6 module和commonJs规范. import是个语句,只能在js代码顶部使用,而require不一样,它是一个表达式,可以进行赋值操作。我们试一下,用require 引入图片是怎么样的效果,在 script 标签时,写下

var img = require('./img/lotus.jpg');console.log(img);

刷新浏览器,在控制台上可以看到如下输出

正好是图片的路径,也正是我们想要的内容,刚才也说了,require是一个表达式,它可以用到任何js 表达式能用到的地方。我这时就想,把后台返回的代码进行重新组装,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: Name,EnName: require(`./img/${item.EnName}.jpg`) // 利用require 引入图片,获得图片路径 }})}})}

这时刷新浏览器,点击按钮发送请求,可以看到图片了并且一一对应,成功了。

这时又一想,既然require是一个表达式,在template模版中是直接可以解析js表达式,那么直接把img的src绑定到require表达式就可以了,把getFlower方法,回退到上一次代码,然后template代码如下

<ul><li v-for ="item in flowers" :key="item.EnName"><img :src="require(`./img/${item.EnName}.jpg`)" alt="flowers"><p>{{Name}}</p></li></ul>

同样也成功了。

最后写代码的时候发现,如果读取的图片不存在,上面的方法就会报错,并且没有办法处理。这时还要回到js的代码处理。我又把html代码回到以前,然后在getFlower方法中进行错误处理,既然读取报错,我们读取的代码就放到try中,如果有报错,就在catch看处理,提供一个默认图片,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'>点击加载请求</button><ul><li v-for ="item in flowers" :key="item.EnName"><img :src="item.EnName" alt="flowers"><p>{{Name}}</p></li></ul></div></template><script>// 引入axios,用于发送请求,defaults 设置后台请求地址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: Name,EnName: img}})}})}}};</script>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。