条件渲染

v-ifv-else-ifv-else在之前的简单使用中已经做过相应的介绍了,这里用一个非常简单的例子做一个使用说明

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
<h2 v-if="sex=='男'">您好,先生</h2>
<h2 v-else-if="sex=='女'">您好,女士</h2>
<h2 v-else>您好,来宾</h2>
</div>
<script>
var app = new Vue({
el:"#app",
data:{
sex: "史莱姆"
}
})
</script>

使用模板进行条件渲染

可以看出,如果我们要进行条件渲染,则必须要将指令加在标签内,但是如果我们希望多个标签同时出现,又不希望嵌套,则可以使用模板template

1
2
3
4
<template v-if="sex=='男'">
<h1>以下内容仅男士可见</h1>
<p>其实也没啥内容</p>
</template>

在页面渲染结果中是不会出现template的,仅作为一个不可见的包裹元素来使用

v-show

除了v-if系列之外,Vue.js还提供了一种条件渲染指令v-show,和v-if的使用方法十分相似

1
2
3
4
<div v-show="sex=='男'">
<h1>以下内容仅男士可见</h1>
<p>其实也没啥内容</p>
</div>

但是v-showv-if在渲染方式上是存在区别的,当v-if判断失效的时候,相应的元素并不会被渲染出来,直到判断为真才会去渲染对应的元素,而v-show不管元素是否生效,都会去渲染它,用display属性来决定元素是否显示,比方说,上面的html代码在data中的sex为”女”时渲染得到的html代码如下

1
2
3
4
5
6
7
<div id="app">
<h2>您好,女士</h2>
<div style="display: none;">
<h1>以下内容仅男士可见</h1>
<p>其实也没啥内容</p>
</div>
</div>

当需要该dom元素可见时,只要改变display属性即可

所以相比之下,v-if的切换开销大,而v-show的初始渲染开销大,当网页需要频繁切换时应使用v-show来渲染,否则v-if更佳

用key来管理元素

Vue的实现会高效的渲染元素,通常会复用已有的元素而非从头开始渲染

比方说如下的例子,点击按钮之后

1
2
3
4
5
6
7
8
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>

输入区域的内容并没有变化,但是label确实发生了变化,说明按钮生效了

本质上,因为两个模板的元素是相同的,Vue并没有重新去渲染一个新的,仅仅是替换了labelinnerHTML以及inputplaceholder而已

如果我们不希望vue去复用元素,我们得告诉vue两个元素是完全独立的,为此,vue为我们提供了一个key属性,你只要给不希望被复用的元素key属性即可

1
2
3
4
5
6
7
8
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>

这样点击按钮的时候输入区域的内容就不会被保留,因为dom被重新生成了

列表渲染

基于数组渲染列表

之前在简单使用中初步了解了v-for,我们知道用v-for可以很方便地遍历data中的数组,如下所示是一个简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
<ul id="app">
<li v-for="item in items">
{{item}}
</li>
</ul>
<script>
var app = new Vue({
el: "#app",
data:{
items: ["item1","item2","item3","item4"]
}
})
</script>

v-for还可以拥有第二个参数,用来表示下标

1
2
3
4
5
<ul id="app">
<li v-for="(item, index) in items">
{{item}},{{index}}
</li>
</ul>

数组的更新检测

对于刚才用数据渲染列表的例子,我们在控制台输入代码

1
app.items[0]="item0"

可以在控制台看到items[0]被修改了,但是页面上却并没有什么变化,因为vue是不监听索引值的,但是vue封装了很多数组的变更方法,这些方法是可以被监听到的,包括

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

还包括了数组替换的方法:filter()、concat() 和 slice()

注意这里的数组替换并不会使得VUE重新渲染整个列表,VUE会最大范围地重用DOM元素,因此这个替换是一个比较高效的操作

如果,一定要用索引值去修改,也不是没有办法,可以使用$set方法,使用方法如下

1
app.$set(app.items,0,"item0")

基于对象渲染列表

当用v-for来遍历对象内容时可以有三个参数:属性值,属性名,以及索引值,示例如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<ul id="app">
<li v-for="(val, key, id) in items">
{{val}},{{key}},{{id}}
</li>
</ul>
<script>
var app = new Vue({
el: "#app",
data:{
items: {
item1: "item-1",
item2: "item-2",
item3: "item-3"
}
}
})
</script>

用key来管理数组元素

我们知道,为了让元素不被复用,需要绑定key来使元素独立

但是在数组的遍历中,我们不能将key直接绑定在索引值上,这种操作会因为VUE的复用策略产生一些神奇的问题

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app">
<ul>
<li v-for="(item, index) in items" :key="index">
<input type="checkbox"> {{ item }}
</li>
</ul>
<button @click="handleClick">删除item1</button>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
items: ["item1", "item2", "item3"]
},
methods: {
handleClick() {
this.items.shift()
}
}
})
</script>

我们在item1的checkbox上打个勾

然后点击按钮删除item1,就会发现item1虽然被删除了,但是item2前面的checkbox也有一个勾

这是因为vue在更新数据的过程中,发现虚拟dom前两项的key和当前dom是相同的,于是选择复用,只是更改了dom中的文本

所以,绑定key的时候最好要选择独一无二的变量来渲染,比如可以修改为如下方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div id="app">
<ul>
<li v-for="(item, index) in items" :key="item.id">
<input type="checkbox"> {{ item.val }}
</li>
</ul>
<button @click="handleClick">删除item1</button>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
items: [
{ val: "item1", id: 1 },
{ val: "item2", id: 2 },
{ val: "item3", id: 3 }
]
},
methods: {
handleClick() {
this.items.shift()
}
}
})
</script>

这样就不会有复用的问题了