0 前言

在 Vue学习笔记8:解决Vue学习笔记7中用v-for指令渲染列表遇到两个问题_PurpleEndurer@5lcto的技术博客_51CTO博客 中,我们通过使用Vue的v-for指令,让 用户可选水果列表 和 显示用户选定水果列表 这两个水果列表的网页元素描述代码都得到了大幅度的精简 ,在小结时提出可以进一步优化 函数showFruit的代码。

下面我们以 Vue学习笔记8:解决Vue学习笔记7中用v-for指令渲染列表遇到两个问题_PurpleEndurer@5lcto的技术博客_51CTO博客 里的最终代码

<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>

来进行改造。


1 第一次尝试

1.1 思路

由于我们已经把水果信息提取并存储到了数组aFruits中

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

并以此为基础使用Vue的v-for指令来循环生成用户可选水果列表 和 显示用户选定水果列表  的网页元素描述代码。

在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");

中,我们主要通过比较输入参数v的值与id分别为pApple、pOrange、pGrape三个<P>标签元素的值(水果名称)进行比较,并根据比较结果来决定标签元素的状态是显示还是隐藏。

其中 pApple、pOrange、pGrape这3个id和三个<P>标签元素的值(水果名称)都已经提取并存储到了数组aFruits中,那么,按理我们也可以在函数showFruit中利用数组aFruits来精简代码。

1.2 修改代码

1.2.1 修改函数showFruit

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");
}

改为【代码1.2.1】

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");
  */
  for (var i=0; i < aFruits.length; i++)
  {
    document.getElementById(aFruits[i].id).style.display  = (v==aFruits[i].value ? "inherit" : "none");
  }  
}

我们通过for循环,逐个调用数组aFruits中的水果对象的id属性和value属性,

其中:

document.getElementById(aFruits[i].id)

是用来获取id为数组aFruitsk中第i个水果对象的id属性值(如'pApple')的<p>标签对象,以便对它进行调整显示状态的操作。

v==aFruits[i].value

是判断传入参数v的值是否与数组aFruitsk中第i个水果对象的value属性值(如'苹果')相同,如果两者的值相同,那么<p>标签就显示,否则<p>标签就隐藏。

1.2.2 修改技术改进说明

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

改为

<p>优化showFruit函数</p>

1.3 第一次尝试的完整代码

修改后的完整代码【代码1.3】如下:

<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");
  */
  for (var i=0; i < aFruits.length; i++)
  {
    document.getElementById(aFruits[i].id).style.display  = (v==aFruits[i].value ? "inherit" : "none");
  }  
}
</script>

<template>

<p>优化showFruit函数</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>

1.4 代码运行效果

Vue学习笔记9:用HTML COM进一步优化Vue学习笔记7的代码_V-for指令


网页上 用户可选水果列表 和 显示用户选定水果列表 都正常显示出来了,但 当我们用鼠标点击选定喜欢的水果后,在选定水果列表这里没有作出响应,把用户选定的水果名称显示出来,把其它水果名称隐藏起来。

Vue学习笔记7:使用v-for指令渲染列表_PurpleEndurer@5lcto的技术博客_51CTO博客 中我们遇到的第2个问题又出现了。

2 调试代码

我们继续修改函数showFruit,插入一条调试语句代码:

alert(aFruits.length);

这条语句将显示水果数组aFruits的长度值,如果代码顺利执行,显示出水果数组aFruits的长度值,就说明我们在showFruits函数中可以正常访问水果数组aFruits里的水果对象属性值,否则说明我们在showFruits函数中不能访问水果数组aFruits里的水果对象属性值。

修改后的showFruits函数代码如下【代码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");
  */
  alert(aFruits.length);//显示水果数组aFruits的长度值
  for (var i=0; i < aFruits.length; i++)
  {
    document.getElementById(aFruits[i].id).style.display  = (v==aFruits[i].value ? "inherit" : "none");
  }  
}

代码运行效果如下:

Vue学习笔记9:用HTML COM进一步优化Vue学习笔记7的代码_HTML COM_02

从代码运行结果看,显示的不是水果数组aFruits的长度值3,而是undefined,这就说明我们在showFruits函数中不能访问水果数组aFruits里的水果对象属性值。

这可能与Vue的工作机制有关,我们暂时不去从这个角度进行分析。

3 用HTML COM来改造函数showFruit

既然我们不能直接不能访问水果数组aFruits里的水果对象属性值,我们换一个角度来思考,这些对象属性值已经通过Vue的v-for指令 输出到了 显示用户选定水果列表 的网页元素描述代码, 是否可以通过HTML COM技术来访问和操作显示用户选定水果列表 的网页元素描述代码,从而解决上面的问题。

3.1 改写代码

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

为了应用HTML COM技术,我们将显示用户选定水果列表的代码从:

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

改为:

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

这里主要做了2处修改

3.1.1.1 对<div v-for="value in aFruits">的修改

1 为<div> 指定了id="divFruit",这样我们可以通过<div>来访问它里面的3个<p>...</p>元素。

2 将 v-for="value in aFruits" 指令移到它里面的子标签<p>里,因为我们希望 v-for指令输出<p>...</p>元素就行了。

3.1.1.2 对<p :id=value.id :style=value.color>的修改

<p>主要是增加了从它的父标签<div>下放的 v-for="value in aFruits" 指令,这样输出的<p>...</p>元素,我们很容易通过HTML COM来访问和操作。

3.1.2 修改函数showFruit

我们将使用HTML COM技术来修改。

对于HTML COM技术不够熟悉的朋友可以先阅读:

用HTML DOM实现有条件地渲染网页元素(上)_PurpleEndurer@5lcto的技术博客_51CTO博客

用HTML DOM实现有条件地渲染网页元素(下)_PurpleEndurer@5lcto的技术博客_51CTO博客

这两篇博文,了解其中的一些基础知识。

我们将函数showFruit的代码从【代码1.2.1】:

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");
  */
  for (var i=0; i < aFruits.length; i++)
  {
    document.getElementById(aFruits[i].id).style.display  = (v==aFruits[i].value ? "inherit" : "none");
  }  
}

改为【代码3.1.2】

function showFruit(v, d)
{
	//输入参数:v: value; d:<div>的id值
  //             
  //alert(v + '  ' + d);//显示传参数v和d的值
	/*
	document.getElementById('pApple').style.display  = (v=='苹果' ? "inherit" : "none");
	document.getElementById('pOrange').style.display = (v=='桔子' ? "inherit" : "none");
	document.getElementById('pGrape').style.display  = (v=='葡萄' ? "inherit" : "none");
	*/

	var oP = document.getElementById(d).children;
	//alert(oP.length)
	for (var i=0; i < oP.length; i++)
	{
		//var o = document.getElementById(aFruits[i].id);
	 	oP[i].style.display  = (v==oP[i].innerText ? "inherit" : "none");
	} //for
} //showFruit()

我们给函数增加了一个传入参数d,它的值将会是<div>的id值'divFruit'。

我们的思路是:

1.使用document.getElementById(d).child获得id为 'divFruit'的<div>标签下面的子标签对象数组oP,oP这个数组的元素就是id分别为pApple、pOrange、pGrape这3个<P>标签对象

2.通过<P>标签对象的属性innerText值(也就是水果名称,如'水果')和传入参数v的值进行比较,并根据比较结果来调整<p>标签的显示状态。

这里有一个问题值得我们思考:

<div>的id值'divFruit',是通过函数showFruit的传入参数来传递,还是直接写在函数showFruit的代码中,也就是把代码

document.getElementById(d).child

直接改写为:

document.getElementById('divFruit').child

这样改写的好处是代码更直观,而且函数showFruit可以减少一个传入参数。不利之处是灵活性减弱,不便于被其它代码调用。

权衡利弊之后,这里我们采用了通过函数showFruit的传入参数来传递的方法。


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

既然我们选择了通过函数showFruit的传入参数的方法来传递<div>的id值'divFruit'。

那么我们还需要修改调用函数showFruit的代码。

调用函数showFruit的代码位于用户可选水果列表的描述代码中。

我们将用户可选水果列表的描述代码从

<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>
<p v-for="value in aFruits" >
	<label>
		<input type="radio" :value=value.value name="fruit" @click="showFruit(value.value,'divFruit')" />
		{{value.value}}
	</label>
</p>

主要的修改就是把:

@click="showFruit(value.value)"

改为

@click="showFruit(value.value,'divFruit')"

这样<div>的id值'divFruit'就会作为showFruit函数的第2个传入参数来传递。

3.1.4 修改技术改进说明

<p>优化showFruit函数</p>
<p>用HTML COM技术优化showFruit函数</p>

2.3 改造后的最终代码

汇总以上修改后的完整代码【代码2.3】如下:

<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, d)
{
	//输入参数:v: value; d:<div>的id值
  //             
  //alert(v + '  ' + d);//显示传参数v和d的值
	/*
	document.getElementById('pApple').style.display  = (v=='苹果' ? "inherit" : "none");
	document.getElementById('pOrange').style.display = (v=='桔子' ? "inherit" : "none");
	document.getElementById('pGrape').style.display  = (v=='葡萄' ? "inherit" : "none");
	*/

	var oP = document.getElementById(d).children;
	//alert(oP.length)
	for (var i=0; i < oP.length; i++)
	{
		//var o = document.getElementById(aFruits[i].id);
	 	oP[i].style.display  = (v==oP[i].innerText ? "inherit" : "none");
	} //for
} //showFruit()

</script>

<template>

<p>用HTML COM技术优化showFruit函数</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,'divFruit')" />
		{{value.value}}
	</label>
</p>


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

</template>

2.4 代码运行的效果

Vue学习笔记9:用HTML COM进一步优化Vue学习笔记7的代码_数组_03

4 小结

我们起初想在函数showFruit中利用数组aFruits来精简代码,但是由于Vue的工作机制的限制,我们在函数showFruit中无法访问数组aFruits。

随后我们换了一个思路,利HTML COM技术来访问和操作显示用户选定水果列表 的网页元素描述代码,从代码行数来说,修改前为3行,修改后仍为3 行,行数看起没有变化。

如果我们要增加3种水果的话,用修改前的方法就需要相应的增加3行代码,而修改后的代码则不需要进行修改,增强了代通用性,减少了维护成本。