條件渲染
v-if
<h1 v-if="ok">Yes</h1>
<h1 v-if="ok">Yes</h1>
<h1 v-else>No</h1>
在<template>元素上使用v-if條件渲染分組
最終的渲染結(jié)果將不包含<template>
元素贸典。
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
v-else
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
v-else
元素必須緊跟在帶v-if
或者v-else-if
的元素的后面箕憾,否則它將不會被識別渤早。
v-else-if
2.1.0 新增
<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else-if="type === 'C'">C</div>
<div v-else>Not A/B/C</div>
v-else-if
也必須緊跟在帶v-if
或者v-else-if
的元素之后经柴。
用key管理可復(fù)用的元素
Vue
會盡可能高效地渲染元素扇苞,通常會復(fù)用已有元素而不是從頭開始渲染录择。這么做除了使Vue
變得非常快之外立美,還有其它一些好處匿又。例如,如果你允許用戶在不同的登錄方式之間切換:
<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>
那么在上面的代碼中切換loginType
將不會清除用戶已經(jīng)輸入的內(nèi)容建蹄。因?yàn)閮蓚€(gè)模板使用了相同的元素碌更,<input>
不會被替換掉——僅僅是替換了它的placeholder
。
這樣也不總是符合實(shí)際需求洞慎,所以Vue
為你提供了一種方式來表達(dá)“這兩個(gè)元素是完全獨(dú)立的痛单,不要復(fù)用它們”。只需添加一個(gè)具有唯一值的key
屬性即可劲腿。
<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>
現(xiàn)在旭绒,每次切換時(shí),輸入框都將被重新渲染焦人。
注意挥吵,<label>
元素仍然會被高效地復(fù)用,因?yàn)樗鼈儧]有添加key
屬性花椭。
v-show
<h1 v-show="ok">Hello!</h1>
帶有v-show
的元素始終會被渲染并保留在DOM中忽匈。v-show
只是簡單地切換元素的CSS屬性display
。
注意矿辽,v-show
不支持<template>
元素丹允,也不支持v-else
。
v-if vs v-show
v-if
是“真正”的條件渲染袋倔,因?yàn)樗鼤_保在切換過程中條件塊內(nèi)的事件監(jiān)聽器和子組件適當(dāng)?shù)乇讳N毀和重建雕蔽。
v-if
也是惰性的:如果在初始渲染時(shí)條件為假,則什么也不做——直到條件第一次變?yōu)檎鏁r(shí)奕污,才會開始渲染條件塊萎羔。
相比之下,v-show
就簡單得多——不管初始條件是什么碳默,元素總是會被渲染贾陷,并且只是簡單地基于CSS進(jìn)行切換缘眶。
一般來說,v-if
有更高的切換開銷髓废,而v-show
有更高的初始渲染開銷巷懈。因此,如果需要非常頻繁地切換慌洪,則使用v-show
較好顶燕;如果在運(yùn)行時(shí)條件很少改變,則使用v-if
較好冈爹。
v-if與v-for一起使用
當(dāng)v-if
與v-for
一起使用時(shí)涌攻,v-for
具有比v-if
更高的優(yōu)先級。
列表渲染
用v-for把一個(gè)數(shù)組對應(yīng)為一組元素
我們用v-for
指令根據(jù)一組數(shù)組的選項(xiàng)列表進(jìn)行渲染频伤。v-for
指令需要使用item in items
形式的特殊語法恳谎,items
是源數(shù)據(jù)數(shù)組并且item
是數(shù)組元素迭代的別名。
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
在v-for
塊中憋肖,我們擁有對父作用域?qū)傩缘耐耆L問權(quán)限因痛。v-for
還支持一個(gè)可選的第二個(gè)參數(shù)為當(dāng)前項(xiàng)的索引。
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
可以用of
替代in
作為分隔符岸更,因?yàn)樗亲罱咏麶avaScript迭代器的語法鸵膏。
<div v-for="item of items"></div>
一個(gè)對象的v-for
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
new Vue({
el: '#v-for-object',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})
也可以提供第二個(gè)的參數(shù)為鍵名。
<div v-for="(value, key) in object">
{{ key }}: {{ value }}
</div>
第三個(gè)參數(shù)為索引怎炊。
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>
在遍歷對象時(shí)谭企,是按Object.keys()
的結(jié)果遍歷,但是不能保證它的結(jié)果在不同的JavaScript引擎下是一致的结胀。
key
當(dāng)Vue.js
用v-for
正在更新已渲染過的元素列表時(shí)赞咙,它默認(rèn)用“就地復(fù)用”策略。如果數(shù)據(jù)項(xiàng)的順序被改變糟港,Vue
將不會移動(dòng)DOM元素來匹配數(shù)據(jù)項(xiàng)的順序, 而是簡單復(fù)用此處每個(gè)元素院仿,并且確保它在特定索引下顯示已被渲染過的每個(gè)元素秸抚。這個(gè)類似Vue 1.x
的track-by="$index"
。
這個(gè)默認(rèn)的模式是高效的歹垫,但是只適用于不依賴子組件狀態(tài)或臨時(shí)DOM狀態(tài) (例如:表單輸入值) 的列表渲染輸出剥汤。
為了給Vue
一個(gè)提示,以便它能跟蹤每個(gè)節(jié)點(diǎn)的身份排惨,從而重用和重新排序現(xiàn)有元素吭敢,你需要為每項(xiàng)提供一個(gè)唯一key
屬性。理想的key
值是每項(xiàng)都有的且唯一的id
暮芭。這個(gè)特殊的屬性相當(dāng)于Vue 1.x
的track-by
鹿驼,但它的工作方式類似于一個(gè)屬性欲低,所以需要用v-bind
來綁定動(dòng)態(tài)值。
<div v-for="item in items" :key="item.id">
<!-- 內(nèi)容 -->
</div>
建議盡可能在使用v-for
時(shí)提供key
畜晰,除非遍歷輸出的DOM內(nèi)容非常簡單砾莱,或者是刻意依賴默認(rèn)行為以獲取性能上的提升。
因?yàn)樗?code>Vue識別節(jié)點(diǎn)的一個(gè)通用機(jī)制凄鼻,key
并不與v-for
特別關(guān)聯(lián)腊瑟,key
還具有其他用途。
數(shù)組更新檢測
變異方法
Vue
包含一組觀察數(shù)組的變異方法块蚌,所以它們也將會觸發(fā)視圖更新闰非。
這些方法有:push()
、pop()
峭范、shift()
财松、unshift()
、splice()
虎敦、sort()
游岳、reverse()
。
替換數(shù)組
變異方法其徙,顧名思義胚迫,會改變被這些方法調(diào)用的原始數(shù)組。相比之下唾那,也有非變異方法访锻,例如:filter()
,concat()
和slice()
闹获。這些不會改變原始數(shù)組期犬,但總是返回一個(gè)新數(shù)組。當(dāng)使用非變異方法時(shí)避诽,可以用新數(shù)組替換舊數(shù)組龟虎。
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
你可能認(rèn)為這將導(dǎo)致Vue
丟棄現(xiàn)有DOM并重新渲染整個(gè)列表。幸運(yùn)的是沙庐,事實(shí)并非如此鲤妥。Vue
為了使得DOM元素得到最大范圍的重用而實(shí)現(xiàn)了一些智能的、啟發(fā)式的方法拱雏,所以用一個(gè)含有相同元素的數(shù)組去替換原來的數(shù)組是非常高效的操作棉安。
注意事項(xiàng)
由于JavaScript的限制,Vue
不能檢測以下變動(dòng)的數(shù)組:
- 當(dāng)你利用索引直接設(shè)置一個(gè)項(xiàng)時(shí)铸抑,例如:
vm.items[indexOfItem] = newValue
- 當(dāng)你修改數(shù)組的長度時(shí)贡耽,例如:
vm.items.length = newLength
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是響應(yīng)性的
vm.items.length = 2 // 不是響應(yīng)性的
為了解決第一類問題,以下兩種方式都可以實(shí)現(xiàn)和vm.items[indexOfItem] = newValue
相同的效果,同時(shí)也將觸發(fā)狀態(tài)更新蒲赂。
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
你也可以使用vm.$set
實(shí)例方法阱冶,該方法是全局方法 Vue.set
的一個(gè)別名:
vm.$set(vm.items, indexOfItem, newValue)
為了解決第二類問題,可以使用splice
凳宙。
vm.items.splice(newLength)</pre>
對象更改檢測注意事項(xiàng)
由于JavaScript的限制熙揍,Vue
不能檢測對象屬性的添加或刪除。
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 現(xiàn)在是響應(yīng)式的
vm.b = 2
// `vm.b` 不是響應(yīng)式的
對于已經(jīng)創(chuàng)建的實(shí)例氏涩,Vue
不能動(dòng)態(tài)添加根級別的響應(yīng)式屬性届囚。但是,可以使用Vue.set(object, key, value)
方法向嵌套對象添加響應(yīng)式屬性是尖。
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
你可以添加一個(gè)新的age
屬性到嵌套的userProfile
對象意系。
Vue.set(vm.userProfile,'age',27)
還可以使用vm.$set
實(shí)例方法,它只是全局Vue.set
的別名饺汹。
vm.$set(vm.userProfile,'age',27)
有時(shí)你可能需要為已有對象賦予多個(gè)新屬性蛔添,比如使用Object.assign()
或_.extend()
。在這種情況下兜辞,應(yīng)該用兩個(gè)對象的屬性創(chuàng)建一個(gè)新的對象迎瞧。所以,如果你想添加新的響應(yīng)式屬性逸吵,不要像這樣:
Object.assign(vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
應(yīng)該這樣做:
vm.userProfile=Object.assign({},vm.userProfile,{
age: 27,
favoriteColor: 'Vue Green'
})
顯示過濾/排序結(jié)果
有時(shí)凶硅,我們想要顯示一個(gè)數(shù)組的過濾或排序副本,而不實(shí)際改變或重置原始數(shù)據(jù)扫皱。在這種情況下足绅,可以創(chuàng)建返回過濾或排序數(shù)組的計(jì)算屬性。
<li v-for="n in evenNumbers">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
在計(jì)算屬性不適用的情況下 (例如韩脑,在嵌套v-for
循環(huán)中) 你可以使用一個(gè)method
方法氢妈。
<li v-for="n in even(numbers)">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
一段取值范圍的v-for
v-for
也可以取整數(shù)。在這種情況下段多,它將重復(fù)多次模板首量。
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
v-for on a <template>
類似于v-if
,你也可以利用帶有v-for
的<template>
渲染多個(gè)元素进苍。
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider"></li>
</template>
</ul>
v-for with v-if
當(dāng)它們處于同一節(jié)點(diǎn)蕾总,v-for
的優(yōu)先級比v-if
更高,這意味著v-if
將分別重復(fù)運(yùn)行于每個(gè)v-for
循環(huán)中琅捏。當(dāng)你想為僅有的一些項(xiàng)渲染節(jié)點(diǎn)時(shí),這種優(yōu)先級的機(jī)制會十分有用递雀。
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
上面的代碼只傳遞了未完成的todos
柄延。
而如果你的目的是有條件地跳過循環(huán)的執(zhí)行,那么可以將v-if
置于外層元素 或<template>
上。
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
一個(gè)組件的v-for
在自定義組件里搜吧,可以像任何普通元素一樣用v-for
市俊。
<my-component v-for="item in items" :key="item.id"></my-component>
2.2.0+的版本里,當(dāng)在組件中使用v-for
時(shí)滤奈,key
現(xiàn)在是必須的摆昧。
然而,任何數(shù)據(jù)都不會被自動(dòng)傳遞到組件里蜒程,因?yàn)榻M件有自己獨(dú)立的作用域绅你。為了把迭代數(shù)據(jù)傳遞到組件里,我們要用props
昭躺。
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
不自動(dòng)將item
注入到組件里的原因是忌锯,這會使得組件與v-for
的運(yùn)作緊密耦合。明確組件數(shù)據(jù)的來源能夠使組件在其他場合重復(fù)使用领炫。
下面是一個(gè)簡單的todo list
的完整例子偶垮。
<div id="todo-list-example">
<input
v-model="newTodoText"
v-on:keyup.enter="addNewTodo"
placeholder="Add a todo"
>
<ul>
<li
is="todo-item"
v-for="(todo, index) in todos"
v-bind:key="todo.id"
v-bind:title="todo.title"
v-on:remove="todos.splice(index, 1)"
></li>
</ul>
</div>
注意這里的is="todo-item"
屬性。這種做法在使用DOM模板時(shí)是十分必要的帝洪,因?yàn)樵?code><ul>元素內(nèi)只有<li>
元素會被看作有效內(nèi)容似舵。這樣做實(shí)現(xiàn)的效果與<todo-item>
相同,但是可以避開一些潛在的瀏覽器解析錯(cuò)誤葱峡。
Vue.component('todo-item', {
template: '\
<li>\
{{ title }}\
<button v-on:click="$emit(\'remove\')">X</button>\
</li>\
',
props: ['title']
})
new Vue({
el: '#todo-list-example',
data: {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes',
},
{
id: 2,
title: 'Take out the trash',
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
},
methods: {
addNewTodo: function () {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
})