v-for
我們用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
塊內(nèi)部寇窑,我們有完全訪問父作用域的屬性。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
作為分隔符, 所以它是最接近JavaScript迭代器的語法
<div v-for="item of items"></div>
Template v-for
如同 v-if
模板甩骏,你也可以用帶有 v-for
的 <template>
標(biāo)簽來渲染多個(gè)元素塊。例如:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider"></li>
</template>
</ul>
對象迭代 v-for
你也可以用 v-for
通過一個(gè)對象的屬性來迭代先慷。
<ul id="repeat-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
new Vue({
el: '#repeat-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>
<p class="tip">當(dāng)遍歷一個(gè)對象時(shí)横漏,順序是根據(jù) Object.keys()
可枚舉鍵名排列,不保證和JavaScript引擎實(shí)現(xiàn)是一致的熟掂。</p>
整數(shù)迭代 v-for
v-for
也可以取整數(shù)缎浇。在這種情況下,它將重復(fù)多次模板
<div>
<span v-for="n in 10">{{ n }}</span>
</div>
組件 和 v-for
了解組件相關(guān)知識赴肚,查看 組件 素跺。
在自定義組件里,你可以像任何普通元素一樣用 v-for
誉券。
<my-component v-for="item in items"></my-component>
然而他不能自動傳遞數(shù)據(jù)到組件里指厌,因?yàn)榻M件有自己獨(dú)立的作用域。為了傳遞迭代數(shù)據(jù)到組件里踊跟,我們要用 props
:
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index">
</my-component>
不自動注入 item
到組件里是因?yàn)檫@樣能讓組件緊密耦合 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:title="todo"
v-on:remove="todos.splice(index, 1)"
></li>
</ul>
</div>
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: [
'Do the dishes',
'Take out the trash',
'Mow the lawn'
]
},
methods: {
addNewTodo: function () {
this.todos.push(this.newTodoText)
this.newTodoText = ''
}
}
})
key
當(dāng)Vue.js用 v-for
正在更新已渲染過的元素列表時(shí)箕憾,它默認(rèn)用 “就地復(fù)用” 策略。如果數(shù)據(jù)項(xiàng)的順序被改變拳昌,而不是移動DOM元素來匹配列表的順序袭异,Vue將簡單復(fù)用此處每個(gè)元素,并且確保它在特定索引下顯示已被渲染過的每個(gè)元素炬藤。這個(gè)類似Vue 1.X的 track-by="$index"
御铃。
這個(gè)默認(rèn)的模式是有效的碴里,但是只適合你的列表渲染輸出時(shí)不依賴子組件狀態(tài)或臨時(shí)DOM狀態(tài)(例如:表單輸入框的值)
給Vue一個(gè)提示以便它能跟蹤每個(gè)節(jié)點(diǎn)身份,并且因此重新使用和重新排序現(xiàn)有元素上真,你需要為每項(xiàng)提供一個(gè)唯一 key
屬性咬腋。一個(gè)有效的 key
值是每項(xiàng)唯一ID. 這個(gè)特殊的屬性相當(dāng)于Vue 1.x的 track-by
,但它像一個(gè)變量睡互,所以你需要用 v-bind
來綁定動態(tài)值(簡潔寫法如下)
<div v-for="item in items" :key="item.id">
<!-- content -->
</div>
它建議盡可能用 v-for
時(shí)提供一個(gè) key
帝火。除非迭代DOM內(nèi)容很簡單,或者你有意要依賴于對性能提升的默認(rèn)行為湃缎。
因?yàn)樗荲ue識別節(jié)點(diǎn)的通用的機(jī)制犀填,key
還具有并不特別依賴于 v-for
的其他用途,我們將在后面的指南中看到其他用途嗓违。
數(shù)組更新檢測
突變方法
Vue包含一組觀察數(shù)組的改變原數(shù)組的方法九巡,所以它們也將會觸發(fā)視圖更新。這些方法如下:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
你打開控制臺蹂季,然后用前面例子的 items
數(shù)組調(diào)用突變方法:example1.items.push({ measage: 'Baz' })
重塑數(shù)組
突變方法冕广,顧名思義,改變原始數(shù)組的稱呼偿洁。相比之下撒汉,也有不改變原組數(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實(shí)現(xiàn)了一些智能化去最大化的重用DOM元素增拥,所以用另外含有重疊對象的數(shù)組替換數(shù)組是非常高效的操作啄巧。
注意事項(xiàng)
由于JavaScript的限制,Vue不能檢測以下變動的數(shù)組:
- 當(dāng)你直接設(shè)置一個(gè)項(xiàng)的索引時(shí), 例如:
vm.items[indexOfItem] = newValue
- 當(dāng)你修改數(shù)組的長度時(shí), 例如:
vm.items.length = newLength
為了避免第一種情況, 以下兩種方式將達(dá)到像 vm.items[indexOfItem] = newValue
的效果掌栅, 同時(shí)也將觸發(fā)狀態(tài)更新:
// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice`
example1.items.splice(indexOfItem, 1, newValue)
避免第二種情況, 使用 splice
:
example1.items.splice(newLength)
顯示過濾/排序結(jié)果
有時(shí)我們無需實(shí)際改變或重置原始數(shù)據(jù)對數(shù)組進(jìn)行過濾或排序秩仆。在這種情況下,你可以創(chuàng)建計(jì)算的屬性返回過濾或排序的數(shù)組渣玲。
例如:
<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))逗概,但是性能是低效的:
<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
})
}
}