用v-for把一個陣列對應為一個元件元素
我們用v-for指令根據一組陣列的選項列表進行渲染。v-for指令需要使用item in items形式的語法:
<ul>
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
var vm = new Vue({
el: '#el',
data: {
items: [
{message: 'foo'},
{message: 'boar'}
]
}
})
在v-for塊中,我們擁有對父作用域屬性的完全訪問許可權。v-for還支援一個可選的第二個引數為當前項的索引。
<ul>
<li v-for="(item, index) in items">
{{ item.message }} {{ index }}
</li>
</ul>
var vm = new Vue({
el: '#el',
data: {
items: [
{message: 'foo'},
{message: 'bar'}
]
}
})
也可以用of替代in作為分隔符,因為它是最接近JavaScript迭代器的語法:
<div v-for="item of items"></div>
一個物件的v-for
也可以使用v-for通過對一個物件的屬性迭代。
new Vue({
el: '#el',
data: {
object: {
firstName: 'h',
lastName: 'z',
age: 26
}
}
})
<ul id="v-for-object" class="demo">
<li v-for="value on object">
{{ value }}
/li>
</ul>
也可以提供第二個引數為名:
<div v-for="(value, key) in object">
{{ key }} : {{ value }}
</div>
第三個引數為索引:
<div v-for="(value, key, index) in object">
{{index}}. {{key}}: {{value}}
</div>
Key
當Vue使用v-for正在更新已渲染過的元素列表時,它預設就地複用。如果資料項的順序被改變,Vue將不會移動DOM元素來匹配資料項的順序,而是簡單的複用此處每個元素,並且 確保它在特定索引下顯示已被渲染過的每個元素。
這個預設的模式是高效的,但只適用於不依賴子元件狀態或零時DOM狀態的列表渲染輸出。
為了給Vue一個提示,以便追蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一key屬性。理想的key值是每項都有唯一id。它的工作方式類似於一個屬性,所以你需要用v-bind來繫結動態值:
<div v-for="item in items" :key="item.id">
</div>
建議儘可能在使用v-for時提供key,除非遍歷輸出的DOM內容非常簡單,或者是刻意依賴預設行為以獲取效能上提升。
陣列更新檢測
(1)變異方法
Vue包含一組觀察陣列的變異方法,所以它們也將會觸發檢視更新。這些方法如下:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
(2)替換陣列
變異方法,是會改變被這些方法呼叫的原始陣列。相比之下也有非變異方法:
filter()
concat()
slice()
這些方法不會改變原始陣列,但是總會返回一個新陣列。當使用非變異方法時,可以用新陣列替換舊陣列:
ex.items = ex.items.filter(function(item) {
return item.message.match(/Foo/)
})
你可能認為這將導致Vue丟棄現有DOM並重新渲染整個列表。Vue為了使得DOM得到最大範圍的重用而實現了一些智慧的、啟發式的方法,所以用一個含有相同元素的陣列去替換原來的陣列是非常高效的操作。
注意事項
由於JavaScript的限制,Vue補鞥呢檢測以下變動的陣列:
1. 當你用索引直接設定一個項的時候:vm.items[indexOfItem] = newValue
2. 當你修改陣列的長度時,例如:vm.items.length = newLenth
舉個例子:
var vm = new Vue({
data: {
items: ['a','b','c']
}
})
vm.items[1] = 'x' //不是響應式的
vm.items.length = 2// 不是響應式的
為了解決第一類問題,以下兩種方式都可以實現vm.items[i] = newVal相同的效果,同時也會觸發響應式更新:
//Vue.set
Vue.set(vm.items, i, newVal)
//Array.prototype.splice
vm.items.splice(i, 1, newVal)
也可以使用vm.$set例項方法,該方法是全域性方法Vue.set的一個別名:
vm.$set(vm.items, i, newVal)
為了解決第二類問題,可以使用splice:
vm.items.splice(newLenght)
物件更改檢測注意事項
由於JavaScript的限制,Vue不能檢測物件屬性的新增或刪除:
var vm = new Vue({
data: {
a: 1
}
})
//vm.a是響應式的
//vm.b不是響應式的
對於已經建立的例項,Vue不能動態新增根級別的響應式屬性,但是可以通過Vue.set(obj,key,value)方法向巢狀物件新增響應式屬性。
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
你可以新增一個新age屬性巢狀的userProfile物件:
Vue.set(vm.userProfile, 'age', 27)
還可以使用vm.$set例項方法,它只是全域性Vu.set的別名:
vm.$set(vm.userProfile, 'age', 27)
有事可能需要為已有物件賦予多個新屬性,所以,如果你想新增新的響應式屬性:
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'vue green'
})
顯示過濾/排序結果
有時我們想要顯示一個陣列的過濾或者排序副本,而不是實際改變原始值,我們可以建立返回過濾或排序陣列的計算屬性:
<li v-for="n in evenNubers">{{ n }}</li>
data: {
number: [1,2,3,4,5]
},
computed: {
evenNubers:function() {
return this.number.reverse()
}
}
在計算屬性不適用的情況下,可以使用method方法。
一段取值範圍的v-for
v-for也可以取整數。在這種情況下,它將重複多次模板。
<div>
<span v-for="n in 10">{{ n }}</span>
</div>
v-for on a <template>
類似於v-if,你也可以利用帶有v-for的<template>渲染多個元素。比如:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
v-for with v-if
當它們處於同一節點,v-for的優先順序比v-if更高,這意味著v-if將分別重複執行於每個v-for迴圈中。當你想僅有的一些項渲染節點時,這種優先順序的機制會十分有用:
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
一個元件的v-for
在自定義元件裡,你可以像任何普通元素一樣用v-for:
<my-component v-for="item in items" :key="item.id"></my-component>
在2.2.0+版本里面。當元件中使用v-for時,key現在是必須的。
然而,任何資料都不會自動傳遞到元件中,因為元件有自己的獨立作用域,為了把迭代資料傳遞到元件裡,我們要用props:
<my-component
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
></my-component>
不自動將item注入到原元件裡的原因是這會使得元件與v-for的運作耦合,明確元件資料的來源能夠使元件在其他場合重複使用。