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的代码通用性不强,维护起来不方法,可以改进一下。


相关文章
|
5天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
4天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
4天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
19天前
|
数据采集 监控 JavaScript
在 Vue 项目中使用预渲染技术
【10月更文挑战第23天】在 Vue 项目中使用预渲染技术是提升 SEO 效果的有效途径之一。通过选择合适的预渲染工具,正确配置和运行预渲染操作,结合其他 SEO 策略,可以实现更好的搜索引擎优化效果。同时,需要不断地监控和优化预渲染效果,以适应不断变化的搜索引擎环境和用户需求。
|
5天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
5天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
5天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
6天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
6天前
|
存储 JavaScript
Vue 组件间如何通信
Vue组件间通信是指在Vue应用中,不同组件之间传递数据和事件的方法。常用的方式有:props、自定义事件、$emit、$attrs、$refs、provide/inject、Vuex等。掌握这些方法可以实现父子组件、兄弟组件及跨级组件间的高效通信。
|
11天前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发