Vue学习笔记8:解决Vue学习笔记7中用v-for指令渲染列表遇到两个问题

简介: Vue学习笔记8:解决Vue学习笔记7中用v-for指令渲染列表遇到两个问题

0 前言

在  Vue学习笔记7:使用v-for指令渲染列表_PurpleEndurer@5lcto的技术博客_51CTO博客 中,我们使用Vue的v-for指令来改造代码,两个水果列表的网页元素描述代码都得到了大幅度的精简,代码变得更清晰,更便于维护。

与此同时,这次改造也引出了两个新的问题:

1.用户选定水果列表中的水果名称没有保留之前设定的颜色,全部以黑色来显示,不够亮丽醒目。

2.当用户选定喜欢的水果后,在选定水果列表这里没有作出响应,把用户选定的水果名称显示出来,把其它水果名称隐藏起来。

出现第1个问题的原因是我们没有把水果的颜色提取到 水果信息数组aFruit中并输出。

出现第2个问题的原因是我们没有把水果的id提取到 水果信息数组aFruit中并输出,而showFruit(v)函数是需要使用id来控制网页元素的。

在解决这两个问题的过程中,我们会发现实际上远没有上面讲的这么简单。

下面以 Vue学习笔记7:使用v-for指令渲染列表_PurpleEndurer@5lcto的技术博客_51CTO博客 中的最终代码:

<script setup>
import { ref } from 'vue'
var aFruits = ref(["苹果", "桔子", "葡萄"]);
/*  
var aFruits = ref({apple:"苹果",  
  orange:"桔子",
  grape: "葡萄"});
*/
 
function showFruit(v)
{
  document.getElementById('pApple').style.display  = (v=='苹果' ? "inherit" : "none");
  document.getElementById('pOrange').style.display = (v=='桔子' ? "inherit" : "none");
  document.getElementById('pGrape').style.display  = (v=='葡萄' ? "inherit" : "none");
}
 
</script>
<template>
<p>用Vue指令v-for循环输出网页元素描述代码</p>
<p style="margin-left:20%; color:purple; font-weight:bold;">
  by PurpleEndurer
</p>
<p>你喜欢哪种水果?</p>
<p v-for="value in aFruits">
  <label>
        <input type="radio" value="{{value}}" name="fruit" @click="showFruit('{{value}}')" />
        {{value}}
  </label>
  <!--
  <textarea>
      <label>
        <input type="radio" value="{{value}}" name="fruit" @click="showFruit('{{value}}')" />
        {{value}}
      </label>
  </textarea>
  //-->
 </p>
<p>你喜欢的是:</p>
<p v-for="value in aFruits">{{value}}</p>
</template>

为基础进行研究与改进。

1 第1次改进代码

1.1 改进水果信息数组

在  Vue学习笔记7:使用v-for指令渲染列表_PurpleEndurer@5lcto的技术博客_51CTO博客 中,我们分析了水果列表1

<p>
  <label>
  <input type="radio" value="苹果" name="fruit" onchange="showFruit(this.value)" />
  苹果
  </label>
</p>
<p>
  <label>
  <input type="radio" value="桔子" name="fruit" onchange="showFruit(this.value)" />
  桔子
  </label>
</p>
<p>
  <label>
  <input type="radio" value="葡萄" name="fruit" onchange="showFruit(this.value)" />
  葡萄
  </label>
</p>

和水果列表2:

<p id="pApple" style="color:red">苹果</p>
<p id="pOrange" style="color:orange">桔子</p>
<p id="pGrape" style="color:purple;">葡萄</p>

其中的有效信息有3项:

id :如pApple

color :如 red

value :如 苹果

当时我们为了突出重点,只使用其中的value这项信息定义了水果信息数组:

var aFruits= ref(["苹果","桔子","葡萄"]);

1.

现在我们要对这个数组进行改进,把id和style两项信息也加进去,形成如下【代码1.1】:

var aFruits = ref([{id:'Apple', color:'red', value:'苹果'},
    {id:'Orange', color:'orange',value:'桔子'},
    {id:'Grape', color:'purple', value:'葡萄'}
  ]);

1.2 改写网页元素描述代码

1.2.1 改造用户可选水果列表的描述代码

之前的代码是:

<p>你喜欢哪种水果?</p>
<p v-for="value in aFruits">
  <label>
        <input type="radio" value="{{value}}" name="fruit" @click="showFruit('{{value}}')" />
        {{value}}
  </label>
  <!--
  <textarea>
      <label>
        <input type="radio" value="{{value}}" name="fruit" @click="showFruit('{{value}}')" />
        {{value}}
      </label>
  </textarea>
  //-->
 </p>

其中value的值就是数组aFruits:

var aFruits= ref(["苹果","桔子","葡萄"]);

1.

的元素,如'苹果',我们直接使用value就行了。

现在水果信息数组aFruits已经从一个一维的字符串数组改进成为一个对象数组:

var aFruits = ref([{id:'Apple', color:'red', value:'苹果'},
    {id:'Orange', color:'orange',value:'桔子'},
    {id:'Grape', color:'purple', value:'葡萄'}
  ]);

对于

<p v-for="value in aFruits">

来说,value的值是一个对象,比如:[{id:'Apple', color:'red', value:'苹果'}

现在我只需要对象中的value属性的值,即value.value。因此描述代码要改为【代码1.2.1】:

<p>你喜欢哪种水果?</p>
<p v-for="value in aFruits">
  <label>
  <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
  {{value.value}}
  </label>
  <!--
  <textarea>
      <label>
      <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
      {{value.value}}
      </label>
  </textarea>
  //-->
</p>

1.2.2 改造显示用户选定水果列表的描述代码

之前的代码是:

<p>你喜欢的是:</p>
<p v-for="value in aFruits">{{value}}</p>

现在水果信息数组aFruits已经从一个一维的字符串数组改进成为一个对象数组,并且我们要把对象中的id、color和value属性值都用上,所以改为【代码1.2.2】:

<div v-for="value in aFruits">
  <p id="{{value.id}}" style="color:{{ value.color }}">
  {{value.value}}
  </p>
</div>

1.2.3 修改技术改进说明

<p>用Vue指令v-for循环输出网页元素描述代码</p>

改为

<p>用Vue指令v-for循环输出网页元素描述代码追加颜色</p>

1.3 第1次改进的最终代码

汇总以上修改后的【代码1.3】为:

<script setup>
import { ref,reactive } from 'vue'
var aFruits = ref([{id:'Apple', color:'red', value:'苹果'},
    {id:'Orange', color:'orange',value:'桔子'},
    {id:'Grape', color:'purple', value:'葡萄'}
  ]);
function showFruit(v)
{
  document.getElementById('pApple').style.display  = (v=='苹果' ? "inherit" : "none");
  document.getElementById('pOrange').style.display = (v=='桔子' ? "inherit" : "none");
  document.getElementById('pGrape').style.display  = (v=='葡萄' ? "inherit" : "none");
}
</script>
<template>
<p>用Vue指令v-for循环输出网页元素描述代码追加颜色</p>
<p style="margin-left:20%; color:purple; font-weight:bold;">
  by PurpleEndurer
</p>
<p>你喜欢哪种水果?</p>
<p v-for="value in aFruits">
  <label>
  <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
  {{value.value}}
  </label>
  <!--
  <textarea>
  <label>
    <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
    {{value.value}}
  </label>
  </textarea>
  //-->
</p>
<p>你喜欢的是:</p>
<div v-for="value in aFruits">
  <p id="{{value.id}}" style="color:{{ value.color }}">
  {{value.value}}
  </p>
</div>
</template>

1.4 第1次改进代码的运行效果

从运行结果来看,不仅用户选定水果列表中的水果名称没有颜色这个问题没解决,而且当用户选定喜欢的水果后,在选定水果列表这里没有作出响应这两个之前说到的问题同样没有解决,此外我们还看到了出错信息:

Cannot read properties of null (reading 'style')

2 调试代码

【代码1.3】看起来是挺完美的,但运行效果不佳,理想和现实有时差距就是这么大。

我们要添加一些辅助的调试代码来分析它运行不如预期的原因。

2.1 增加调试代码

2.1.1 修改用户可选水果列表的描述代码

将【代码1.2.1】

<p>你喜欢哪种水果?</p>
<p v-for="value in aFruits">
  <label>
  <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
  {{value.value}}
  </label>
  <!--
  <textarea>
      <label>
      <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
      {{value.value}}
      </label>
  </textarea>
  //-->
</p>

改为【代码 2.1.1】:

<p>你喜欢哪种水果?</p>
<p v-for="value in aFruits">
  <label>
  <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
  {{value.value}}
  </label>
  <textarea>
      <label>
    <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
    {{value.value}}
      </label>
  </textarea>
</p>

我们把原先注释起来的<textarea>……</textarea>重新启用,用来查看一下Vue生成的代码。

2.1.2 修改显示用户选定水果列表的描述代码

为了观察Vue生成的代码,我们也给【代码1.2.2】

<div v-for="value in aFruits">
  <p id="{{value.id}}" style="color:{{ value.color }}">
  {{value.value}}
  </p>
</div>

增加<textarea>……</textarea>,变为【代码2.1.2】:

<div v-for="value in aFruits">
  <p id="{{value.id}}" style="color:{{ value.color }}">
  {{value.value}}
  </p>
  <textarea>
  <p id="{{value.id}}" style="color:{{ value.color }}">
    {{value.value}}
  </p>
  </textarea>
</div>

2.1.3 修改showFruit(v)函数

我们看到的出错信息:

Cannot read properties of null (reading 'style')

应该是执行showFruit(v)函数中的代码引起的,而且很可能跟传入参数v的值有关,所以我们给showFruit(v)函数的函数体【代码】:

function showFruit(v)
{
  document.getElementById('pApple').style.display  = (v=='苹果' ? "inherit" : "none");
  document.getElementById('pOrange').style.display = (v=='桔子' ? "inherit" : "none");
  document.getElementById('pGrape').style.display  = (v=='葡萄' ? "inherit" : "none");
}

增加一条语句:alert(v),来显示传入参数v的值,即【代码2.1.2】

function showFruit(v)
{
  alert(v);//显示传参数v的值
  document.getElementById('pApple').style.display  = (v=='苹果' ? "inherit" : "none");
  document.getElementById('pOrange').style.display = (v=='桔子' ? "inherit" : "none");
  document.getElementById('pGrape').style.display  = (v=='葡萄' ? "inherit" : "none");
}


2.2 调试代码

增加以上调试代码后的最终代码【代码2.2】如下:

<script setup>
import { ref,reactive } from 'vue'
var aFruits = ref([{id:'pApple', color:'red', value:'苹果'},
    {id:'pOrange', color:'orange',value:'桔子'},
    {id:'pGrape', color:'purple', value:'葡萄'}
  ]);
function showFruit(v)
{
  alert(v);//显示传参数v的值
  document.getElementById('pApple').style.display  = (v=='苹果' ? "inherit" : "none");
  document.getElementById('pOrange').style.display = (v=='桔子' ? "inherit" : "none");
  document.getElementById('pGrape').style.display  = (v=='葡萄' ? "inherit" : "none");
}
</script>
<template>
<p>用Vue指令v-for循环输出网页元素描述代码追加颜色</p>
<p style="margin-left:20%; color:purple; font-weight:bold;">
  by PurpleEndurer
</p>
<p>你喜欢哪种水果?</p>
<p v-for="value in aFruits">
  <label>
  <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
  {{value.value}}
  </label>
  <textarea>
      <label>
    <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
    {{value.value}}
      </label>
  </textarea>
</p>
<p>你喜欢的是:</p>
<div v-for="value in aFruits">
  <p id="{{value.id}}" style="color:{{ value.color }}">
  {{value.value}}
  </p>
  <textarea>
  <p id="{{value.id}}" style="color:{{ value.color }}">
    {{value.value}}
  </p>
  </textarea>
</div>
</template>

2.3 调试代码运行效果

从<textarea></textarea>中的显示的代码来看,aFruits数组中各个对象的属性都在{{}}中成功解包引用出来了。

但是代码没有生效,比如显示用户选定水果列表的第1项的描述代码:

<p id="Apple" style="color:red">
    苹果
  </p>

已经通过style的color指定了红色,但是页面上显示出来的‘苹果’仍然是黑色。

我们再用鼠标操作,点击选择水果看看是什么效果:

当我们点击选择自己的喜欢的水果,比如苹果后,会执行showFruit(v)函数,我们把所点水果的value(按理来说就是'苹果')作为showFruit函数传入参数值赋给v。

在showFruit(v)函数内容,会首先显示传入参数v的值,按理来说应该显示的是‘苹果’,但实际显示的是:

这说明在【代码2.1.1】中的语句:

<input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />

@click="showFruit('{{value.value}}')"

引用的{{value.value}} 没有成功解包引用出来。

3 分析原因

经过认真分析思考和反复测试,梳理出了引起问题的原因:

3.1 HTML标签中的属性书写语法错误

HTML标签中的属性,如果需要引用数据的,要使用v-bind指令进行绑定。

比如,用户可选水果列表的描述代码【代码1.2.1】中的

<input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />

1.

正确写法是

<input type="radio" :value=value.value name="fruit" @click="showFruit(value.value)" />

1.

<input>标签的value属性要引用水果信息数组aFruits中对象的value属性,可以写为:

v-bind:value=value.value

1.

由于“v-bind:”指令可以简写为“:”,所以我们通常写为:

:value=value.value

1.

3.2 HTML标签内部引用数据不需要{{}}

在HTML标签内部引用数据时,数据不需要使用{{}}来包括。

比如,用户可选水果列表的描述代码【代码1.2.1】中的

<input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />

1.

<input>标签的click事件的监听函函要将水果信息数组aFruits中对象的value属性值作为传入参数值,代码:

@click="showFruit('{{value.value}}')" />

1.

这种写法是错误的,正确的写法写为:

@click="showFruit(value.value)"

1.

3.3 函数showFruit中使用的id值与aFruits中定义的id值不匹配

函数showFruit中语句:

document.getElementById('pApple').style.display  = (v=='苹果' ? "inherit" : "none");
  document.getElementById('pOrange').style.display = (v=='桔子' ? "inherit" : "none");
  document.getElementById('pGrape').style.display  = (v=='葡萄' ? "inherit" : "none");

document.getElementById()使用的id值pApple、pOrange、pGrape均是以p开头的

而在数组aFruits中:

var aFruits = ref([{id:'Apple', color:'red', value:'苹果'},
    {id:'Orange', color:'orange',value:'桔子'},
    {id:'Grape', color:'purple', value:'葡萄'}
  ]);

我在提取id信息时,把开头的字母p去掉了。

4 第2次改进代码

4.1 改写JavaScript脚本

4.1.1 改进水果信息数组

将【代码1.1】

var aFruits = ref([{id:'Apple', color:'red', value:'苹果'},
    {id:'Orange', color:'orange',value:'桔子'},
    {id:'Grape', color:'purple', value:'葡萄'}
  ]);

改为【代码4.1.1】

var aFruits = ref([{id:'Apple', color:'red', value:'苹果'},
    {id:'Orange', color:'orange',value:'桔子'},
    {id:'Grape', color:'purple', value:'葡萄'}
  ]);

作了2点改动:

1.给所有对象的id值的开头加上p。

2.将color属性性从 color:'颜色' 改为color:'color:颜色' ,如:color:'red' 改为  color:'color:red'。这样修改是方便 显示用户选定水果列表的描述代码的使用。

4.2 改写网页元素描述代码

4.2.1 改写用户可选水果列表的描述代码

将【代码 2.1.1】

<p>你喜欢哪种水果?</p>
<p v-for="value in aFruits">
  <label>
  <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
  {{value.value}}
  </label>
  <!--
  <textarea>
      <label>
      <input type="radio" value="{{value.value}}" name="fruit" @click="showFruit('{{value.value}}')" />
      {{value.value}}
      </label>
  </textarea>
  //-->
</p>

改写为【代码 4.2.1】

<p>你喜欢哪种水果?</p>
<p v-for="value in aFruits" >
  <label>
  <input type="radio" :value=value.value name="fruit" @click="showFruit(value.value)" />
  {{value.value}}
  </label>
</p>

4.2.2 改造显示用户选定水果列表的描述代码

将【代码1.2.2】:

<div v-for="value in aFruits">
  <p id="{{value.id}}" style="color:{{ value.color }}">
  {{value.value}}
  </p>
</div>

改写为【代码4.2.2】:

<p>你喜欢的是:</p>
<div v-for="value in aFruits">
  <p :id=value.id :style=value.color>
  {{value.value}}
  </p>
</div>

4.3 第2次改进的最终代码

综合汇总以上修改的最终代码如下:

<script setup>
import { ref } from 'vue'
var aFruits = ref([{id:'pApple', color:'color:red', value:'苹果'},
    {id:'pOrange', color:'color:orange',value:'桔子'},
    {id:'pGrape', color:'color:purple', value:'葡萄'}
  ]);
function showFruit(v)
{
  //alert(v);//显示传参数v的值
  document.getElementById('pApple').style.display  = (v=='苹果' ? "inherit" : "none");
  document.getElementById('pOrange').style.display = (v=='桔子' ? "inherit" : "none");
  document.getElementById('pGrape').style.display  = (v=='葡萄' ? "inherit" : "none");
}
</script>
<template>
<p>用Vue指令v-for循环输出网页元素描述代码追加颜色</p>
<p style="margin-left:20%; color:purple; font-weight:bold;">
  by PurpleEndurer
</p>
<p>你喜欢哪种水果?</p>
<p v-for="value in aFruits" >
  <label>
  <input type="radio" :value=value.value name="fruit" @click="showFruit(value.value)" />
  {{value.value}}
  </label>
</p>
<p>你喜欢的是:</p>
<div v-for="value in aFruits">
  <p :id=value.id :style=value.color>
  {{value.value}}
  </p>
</div>
</template>

4.4 第2次改进代码的运行效果

从运行效果来看,两个问题都解决了。

5 小结

我们通过两次改进代码,认真分析问题和反复测试,找出了引发问题的原因,顺利解决了之前遇到的两个问题。

在解决问题的过程中有两点收获。

5.1 基础知识要学得扎实

引发问题的原因,基本上都是基础知识掌握得不够扎实。

所以我们学习新知识,不能急功好进,好大喜功,而要稳扎稳打,叫透基础知识,在后面就可以少费时间少走弯路。

5.2 一些改进方向

5.2.1 关于HTML标签的属性引用的数据的实现方法

对于要HTML标签的属性要引用的数据的情况,除了可以使用vue提供的v-bind指令进行绑定这种方法外,我们还可以考虑在使用v-for指令循环生成HTML标签后,再使用window.onload或setTimeout()过一定时间后使用HTML COM访问生成的HTML标签来设置属性值。

5.2.2 改进函数showFruit

函数showFruit的代码通用性不强,维护起来不方法,可以改进一下。


相关文章
|
2月前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
301 2
|
1月前
|
缓存 JavaScript
vue中的keep-alive问题(2)
vue中的keep-alive问题(2)
280 137
|
5月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
771 0
|
5月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
6月前
|
JavaScript 数据可视化 前端开发
基于 Vue 与 D3 的可拖拽拓扑图技术方案及应用案例解析
本文介绍了基于Vue和D3实现可拖拽拓扑图的技术方案与应用实例。通过Vue构建用户界面和交互逻辑,结合D3强大的数据可视化能力,实现了力导向布局、节点拖拽、交互事件等功能。文章详细讲解了数据模型设计、拖拽功能实现、组件封装及高级扩展(如节点类型定制、连接样式优化等),并提供了性能优化方案以应对大数据量场景。最终,展示了基础网络拓扑、实时更新拓扑等应用实例,为开发者提供了一套完整的实现思路和实践经验。
834 77
|
3月前
|
缓存 前端开发 大数据
虚拟列表在Vue3中的具体应用场景有哪些?
虚拟列表在 Vue3 中通过仅渲染可视区域内容,显著提升大数据列表性能,适用于 ERP 表格、聊天界面、社交媒体、阅读器、日历及树形结构等场景,结合 `vue-virtual-scroller` 等工具可实现高效滚动与交互体验。
426 1
|
4月前
|
人工智能 JSON JavaScript
VTJ.PRO 首发 MasterGo 设计智能识别引擎,秒级生成 Vue 代码
VTJ.PRO发布「AI MasterGo设计稿识别引擎」,成为全球首个支持解析MasterGo原生JSON文件并自动生成Vue组件的AI工具。通过双引擎架构,实现设计到代码全流程自动化,效率提升300%,助力企业降本增效,引领“设计即生产”新时代。
403 1
|
4月前
|
JavaScript 安全
在 Vue 中,如何在回调函数中正确使用 this?
在 Vue 中,如何在回调函数中正确使用 this?
259 0
|
5月前
|
JavaScript 前端开发 开发者
Vue 自定义进度条组件封装及使用方法详解
这是一篇关于自定义进度条组件的使用指南和开发文档。文章详细介绍了如何在Vue项目中引入、注册并使用该组件,包括基础与高级示例。组件支持分段配置(如颜色、文本)、动画效果及超出进度提示等功能。同时提供了完整的代码实现,支持全局注册,并提出了优化建议,如主题支持、响应式设计等,帮助开发者更灵活地集成和定制进度条组件。资源链接已提供,适合前端开发者参考学习。
465 17