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


Posted in Javascript onSeptember 03, 2018

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

解决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() {}
 }
};

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

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

现在再来写后台代码, 用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>{{item.CnName}}</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;
  }
 })
 }
 }
};

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

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

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

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

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

那么我们现在要做的就是把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);

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

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

正好是图片的路径,也正是我们想要的内容,刚才也说了,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: item.CnName,
   EnName: require(`./img/${item.EnName}.jpg`) // 利用require 引入图片,获得图片路径
   }
  })
  }
 })
 }

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

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

这时又一想,既然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>{{item.CnName}}</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>{{item.CnName}}</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: item.CnName,
   EnName: img
   }
  })
  }
 })
 }
 }
};
</script>

以上这篇解决vue的 v-for 循环中图片加载路径问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript While 循环基础教程
Apr 05 Javascript
javascript 基础篇4 window对象,DOM
Mar 14 Javascript
如何实现textarea里的不同文本显示不同颜色
Jan 20 Javascript
javascript中解析四则运算表达式的算法和示例
Aug 11 Javascript
jQuery中$this和$(this)的区别介绍(一看就懂)
Jul 06 Javascript
JavaScript获取各大浏览器信息图示
Nov 20 Javascript
jquery 动态合并单元格的实现方法
Aug 26 Javascript
利用jquery实现下拉框的禁用与启用
Dec 07 Javascript
基于JS实现二维码图片固定在右下角某处并跟随滚动条滚动
Feb 08 Javascript
Node.js v8.0.0正式发布!看看带来了哪些主要新特性
Jun 02 Javascript
jQueryUI Sortable 应用Demo(分享)
Sep 07 jQuery
VUE子组件向父组件传值详解(含传多值及添加额外参数场景)
Sep 01 Javascript
Vue实现底部侧边工具栏的实例代码
Sep 03 #Javascript
Angular动态绑定样式及改变UI框架样式的方法小结
Sep 03 #Javascript
node.js使用免费的阿里云ip查询获取ip所在地【推荐】
Sep 03 #Javascript
react在安卓中输入框被手机键盘遮挡问题的解决方法
Sep 03 #Javascript
Vue 中对图片地址进行拼接的方法
Sep 03 #Javascript
VUE预渲染及遇到的坑
Sep 03 #Javascript
详解vue通过NGINX部署在子目录或者二级目录实践
Sep 03 #Javascript
You might like
php面向对象全攻略 (十四) php5接口技术
2009/09/30 PHP
php析构函数的简单使用说明
2015/08/24 PHP
php基于PDO连接MSSQL示例DEMO
2016/07/13 PHP
php 7新特性之类型申明详解
2017/06/06 PHP
新手入门常用代码集锦
2007/01/11 Javascript
在父页面调用子页面的JS方法
2013/09/29 Javascript
JavaScript伸缩的菜单简单示例
2013/12/03 Javascript
js保留小数点后几位的写法
2014/01/03 Javascript
JavaScript获取DOM元素的11种方法总结
2015/04/25 Javascript
BootStrap实现树形目录组件代码详解
2016/06/21 Javascript
jQuery数组处理函数整理
2016/08/03 Javascript
使用JS正则表达式 替换括号,尖括号等
2016/11/29 Javascript
Angular 2父子组件数据传递之@Input和@Output详解(下)
2017/07/05 Javascript
Vue.js中组件中的slot实例详解
2017/07/17 Javascript
JavaScript实现二叉树的先序、中序及后序遍历方法详解
2017/10/26 Javascript
Angular 开发学习之Angular CLI的安装使用
2017/12/31 Javascript
基于jquery的on和click的区别详解
2018/01/15 jQuery
新手快速上手webpack4打包工具的使用详解
2019/01/28 Javascript
[55:18]Liquid vs Chaos 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
Python 'takes exactly 1 argument (2 given)' Python error
2016/12/13 Python
Python实现的微信支付方式总结【三种方式】
2019/04/13 Python
pandas数据筛选和csv操作的实现方法
2019/07/02 Python
深入浅析Python科学计算库Scipy及安装步骤
2019/10/12 Python
Keds官方网站:购买帆布运动鞋和经典皮鞋
2016/11/12 全球购物
联想马亚西亚官方网站:Lenovo Malaysia
2018/09/19 全球购物
外贸实习生自荐信范文
2013/11/24 职场文书
大学生职业生涯规划书范文
2014/01/04 职场文书
公证书标准格式
2014/04/10 职场文书
蟋蟀的住宅教学反思
2014/04/26 职场文书
法人委托书的范本格式
2014/09/11 职场文书
社保转移委托书范本
2014/10/08 职场文书
资料员岗位职责
2015/02/10 职场文书
期末个人总结范文
2015/02/13 职场文书
法律意见书范文
2015/05/20 职场文书
和领导吃饭祝酒词
2015/08/11 职场文书
大学生社区义工服务心得体会
2016/01/22 职场文书