Vue:条件渲染 & 列表渲染
- 条件渲染
- v-show
- v-if
- 列表渲染
- v-for
- 数组
- 对象
条件渲染
Vue
允许依据一定的条件,通过表达式的布尔值,来决定是否渲染某些元素,其依赖于v-show
和v-if
两条指令。
v-show
v-show
可以依据表达式的布尔值,来显示或隐藏元素。
语法:
<标签 v-show="布尔表达式"> </标签>
当布尔表达式为true
,那么渲染该标签,如果为false
,则不渲染。
示例:
<h2 v-show="false"> hello </h2>
<h2 v-show="1 === 1"> world </h2>
第一个表达式为false
,不渲染该标签,第二个表达式为1 === 1
,也就是true
,渲染该标签。
输出结果:
只有第二个world
被渲染了,第一个hello
被隐藏了。查看HTML
页面结构,可以看出其是通过display: none
属性实现的元素隐藏。
v-if
v-if
的功能与v-show
类似,但是其更加激进,而且可以配合v-else
等指令一起使用。
语法:
<标签 v-if="布尔表达式"> </标签>
示例:
<h2 v-if="false"> hello</h2>
<h2 v-if="1 === 1"> world </h2>
把刚才的v-show
改为v-if
。
输出结果:
虽然也只输出了world
,但是其隐藏元素的方式和v-show
不同,此处hello
直接消失了,根本没有这个DOM
元素。
因此对于高频率替换显示与隐藏的标签,建议使用v-show
,其只修改属性而不增删DOM
元素,效率更高。
v-if
还可以配合v-else-if
和v-else
使用,进行多分支条件判断:
语法:
<标签 v-if="布尔表达式"> </标签>
<标签 v-else-if="布尔表达式"> </标签>
<标签 v-else-if="布尔表达式"> </标签>
......
<标签 v-else="布尔表达式"> </标签>
其中v-else-if
和v-else
前面,必须存在v-if
。
示例:
<p>当前的n值是:{{n}}</p>
<button @click="n++">n+1</button> </br>
<div v-if="n === 1">Vue:v1</div>
<div v-else-if="n === 2">Vue:v2</div>
<div v-else-if="n === 3">Vue:v3</div>
<div v-else>Vue:latest</div>
n
是vm.data
下的一个属性,初始值为1
,每次点击按钮自增,都会使n++
并且重新渲染模板,依据条件判断,渲染不同的节点。
输出结果:
起初值为1
,触发v-if
。
当n > 3
时,触发v-else
,输出Vue:latest
。
v-if
或v-show
也经常添加到一个父级元素上,当元素被隐藏,所有子元素也会一起隐藏。
<h2 v-if="n === 1">hello</h2>
<h2 v-if="n === 1">JavaScript</h2>
<h2 v-if="n === 1">Vue</h2>
例如以上代码,可以只使用一个v-if
一次性对多个元素进行条件渲染:
<div v-if="n === 1">
<h2>hello</h2>
<h2>JavaScript</h2>
<h2>Vue</h2>
</div>
但是这样三个元素最外层会多出一层div
:
在部分场景下,最外层的div
可能会影响内部的元素,此时可以使用<template>
标签:
<template v-if="n === 1">
<h2>hello</h2>
<h2>JavaScript</h2>
<h2>Vue</h2>
</template>
输出结果:
这种情况下,三个<h2>
标签外层直接就是root
,没有多出来的<div>
了。
列表渲染
v-for
当拿到一个数组或者对象时,如果需要遍历输出所有的元素,那么v-for
指令可以很方便的完成该功能,且无需手动写循环。
语法:
<标签 v-for="元素 in/of 数组/对象" :key="键"> </标签>
中间的关键字,既可以是in
也可以是of
。
数组
当v-for
遍历数组时,元素可以接收两个参数,格式如下:
<标签 v-for="(元素值, 下标) in/of 数组" :key="键"> </标签>
暂时忽略这个:key
,不写该值。
示例:
<div id="root">
<ul>
下标 姓名 年龄
<li v-for="(p,index) of persons">
{{index}} - {{p.name}} - {{p.age}}
</li>
</ul>
</div>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:19},
{id:'003',name:'王五',age:20}
],
}
})
</script>
在Vue
实例中,有一个数组persions
,内含三个对象,在<li>
中通过v-for
遍历该数组,输出所有值。
其中(p,index) of persons
表示,遍历persons
数组,每次将拿到的元素放到p
中,该元素的下标放到index
中。
在模板内部,可以通过{{}}
插值语法直接使用这些值。
输出结果:
这样就成功渲染了所有对象,但是有一个很大的问题,那就是没有使用:key
这个参数。
在数组操作中,如果没有key
,那么默认为index
,但这是一个不太安全的行为。
简单修改一下HTML
结构:
<ul>
下标 姓名 年龄
<li v-for="(p,index) of persons" :key="index">
{{index}} - {{p.name}} - {{p.age}} <input>
</li>
</ul>
每一个选项,都添加一个<input>
输入框。
启动后,为每个输入框输入对应的姓名:
在控制台中,为数组头部增加一个元素赵六:
奇怪的事情发生了,张三的输入框到了赵六后面,李四的输入框到了张三后面,所有输入框都错位了,这就是:key=index
惹的祸。
当模板重新解析时,v-for
不会重新生成所有的DOM
元素,而是尽可能复用原先的元素,而元素复用依赖于key
的设定。
如下图:
由于默认情况下:key=index
,Vue
认为更新前后key
相同的选项之间,可以进行复用。
插入新元素后,重新解析模板。v-for
进行第一轮循环,遍历到赵六key=index=0
,于是查看原先index=0
的位置,也没有可以复用的元素,发现<input>
可以复用,于是把原先index=0
的<input>
进行复用,放到赵六的后面。
后续同理,key=index=1
时,复用原先index=1
位置的<input>
,导致拿到了错位的数据。
直到key=index=4
时,发现原先没有该数据,生成一个新的元素<input>
。
可以理解为,原先index=0
的位置的元素,被新的index=0
的位置的元素复用了,就是因为key=index
。因此,key
一般不设置为数组下标,而是每个数组元素的唯一id
。
<ul>
下标 姓名 年龄
<li v-for="(p,index) of persons" :key="p.id">
{{index}} - {{p.name}} - {{p.age}} <input>
</li>
</ul>
在每个数组元素中,都设置了对应的id
,指定:key="p.id"
。
和之前一样,插入一个新元素:
这一次由于更新前后,每个数组元素的id
不变,所以<input>
也正确匹配了。
对象
当v-for
遍历对象时,元素也可以接收两个参数,格式如下:
<标签 v-for="(值, 键) in/of 对象" :key="键"> </标签>
当遍历的是对象时,第一个参数接收值,第二个参数接收键,:key
一般指定为属性名
,因为一个对象插入或删除元素后,每个属性的名称是不变的。
示例:
<div id="root">
<ul>
<li v-for="(value, k) of mouse" :key="k">
{{k}}: {{value}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
mouse:{
brand:'Logitech',
price:'199',
color:'black'
}
}
})
</script>
在data
中,放了一个鼠标对象,包括其品牌,售价,颜色三个属性。通过v-for
遍历输出这个对象,k
拿到属性名,value
拿到属性值。
输出结果: