列表渲染
v-for
v-for可以把數據中的一個數組對應爲一組元素
v-for 指令需要以 item in items 形式的特殊語法, items 是源數據數組並且 item 是數組元素迭代的別名。
<li v-for="item in items">{{item.text}}</li>
data:{
items:[
{text:"第一組"},
{text:"第二組"},
{text:"第三組"},
]
}
輸出HTML
第一組
第二組
第三組
在 v-for 塊中,我們擁有對父作用域屬性的完全訪問權限。 v-for 還支持一個可選的第二個參數爲當前項的索引。
<li v-for="(item, index) in items">
{{ index }} - {{ item.text }}
</li>
輸出HTML
1 - 第一組
2 - 第二組
3 - 第三組
你也可以用 of 替代 in 作爲分隔符,因爲它是最接近 JavaScript 迭代器的語法:
<li v-for="item of items">
{{ item.text }}
</li>
一個對象的 v-for
你也可以用 v-for 通過一個對象的屬性來迭代。
<li v-for="item of items">
{{item}}
</li>
data:{
items:{
text1:"第一組",
text2:"第二組",
text3:"第三組",
}
}
輸出HTML
第一組
第二組
第三組
你也可以提供第二個的參數爲鍵名:
<li v-for="(item,key) of items">
{{key}} : {{item}}
</li>
輸出HTML
text1 : 第一組
text2 : 第二組
text3 : 第三組
第三個參數爲索引:
<li v-for="(item,key,index) of items">
{{index}} . {{key}} : {{item}}
</li>
輸出HTML
0 . text1 : 第一組
1 . text2 : 第二組
2 . text3 : 第三組
key
當 Vue.js 用 v-for 正在更新已渲染過的元素列表時,它默認用 “就地複用” 策略。如果數據項的順序被改變,Vue將不是移動 DOM 元素來匹配數據項的順序, 而是簡單複用此處每個元素,並且確保它在特定索引下顯示已被渲染過的每個元素。這個類似 Vue 1.x 的 track-by="$index" 。
這個默認的模式是高效的,但是隻適用於不依賴子組件狀態或臨時 DOM 狀態(例如:表單輸入值)的列表渲染輸出。
爲了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要爲每項提供一個唯一 key 屬性。理想的 key 值是每項都有的且唯一的 id。這個特殊的屬性相當於 Vue 1.x 的 track-by ,但它的工作方式類似於一個屬性,所以你需要用 v-bind 來綁定動態值(在這裏使用簡寫):
<div v-for="item in items" :key="item.id">
<!-- 內容 -->
</div>
建議儘可能使用 v-for 來提供 key ,除非 DOM 內容遍歷起來非常簡單,或者你是有意識的要依賴於默認行爲以便獲得性能提升。
因爲它是 Vue 識別節點的一個通用機制, key 並不特別與 v-for 關聯,key 還具有其他用途,我們將在後面的指南中看到其他用途。
一個組件的v-for
2.2.0+ 的版本里,當在組件中使用 v-for 時,key 現在是必須的。
在自定義組件裏,你可以像任何普通元素一樣用 v-for 。
<mycom v-for="(item,index) in todo" :key="index"></mycom>
Vue.component('mycom', {
template: "<h1>瘋狂的石頭</h1>"
})
var vm = new Vue({
el:"#box",
data:{
todo:[
{text:1,ok:true},
{text:2,ok:false},
{text:3,ok:true},
]
}
})
瘋狂的石頭
瘋狂的石頭
瘋狂的石頭
但是我們又如何將數據渲染到我們的組件中呢?現在我們就需要綁定一個屬性,屬性需要在組件中註冊
<mycom v-for="(item,index) in todo" :key="index" :lie="item.text"></mycom>
Vue.component('mycom', {
template: "<h1>瘋狂的石頭{{this.lie}}</h1>",
props:["lie"]
})
var vm = new Vue({
el:"#box",
data:{
todo:[
{text:1,ok:true},
{text:2,ok:false},
{text:3,ok:true},
]
}
})
輸出HTML
瘋狂的石頭1
瘋狂的石頭2
瘋狂的石頭3
v-for 與 < template >
我們也可以使用 v-for 來渲染 < template >標籤。例如:
<template v-for="item in todo">
<div>{{ item.text }}</div>
</template>
data:{
todo:[
{text:1,ok:true},
{text:2,ok:false},
{text:3,ok:true},
]
}
輸出HTML
1
2
3
數組更新檢測
變異方法
變異方法(mutation method),顧名思義,會改變被這些方法調用的原始數組。
Vue 包含一組觀察數組的變異方法,所以它們也將會觸發視圖更新。這些方法如下:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
非變異方法
相非變異(non-mutating method)方法,例如: filter(), concat() 和 slice() 。這些不會改變原始數組,但總是返回一個新數組。當使用非變異方法時,可以用新數組替換舊數組:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
你可能認爲這將導致 Vue 丟棄現有 DOM 並重新渲染整個列表。幸運的是,事實並非如此。 Vue 爲了使得 DOM 元素得到最大範圍的重用而實現了一些智能的、啓發式的方法,所以用一個含有相同元素的數組去替換原來的數組是非常高效的操作。
注意事項
由於 JavaScript 的限制, Vue 不能檢測以下變動的數組:
-
當你利用索引直接設置一個項時,例如: vm.items[indexOfItem] = newValue
-
當你修改數組的長度時,例如: vm.items.length = newLength
爲了解決第一類問題,以下兩種方式都可以實現和 vm.items[indexOfItem] = newValue 相同的效果, 同時也將觸發狀態更新:
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)
爲了解決第二類問題,你可以使用 splice:
example1.items.splice(newLength)
對象更新檢測
我們可以用以下三種方法對對象進行更新:
如果你需要爲對象屬性之中添加新的屬性,那麼我麼你可以利用以下兩種方法
Vue.set("目標對象","屬性","值")
vm.$set("目標對象","屬性","值")
如果我們想更新對象中的屬性,以下這種方法可以滿足你
this.userProfile = Object.assign({}, this.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
this.userProfile //對象本身的屬性
Object.assign() //es6新增加的方法,用來將源對象的所有可枚舉屬性,複製到目標對象。它至少需要兩個對象作爲參數,第一個參數是目標對象,後面的參數都是源對象
{} //你需要增加的屬性
如果目標對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆蓋前面的屬性。
-
注意!我們不更改根屬性的屬性,只能更改跟屬性以下的子屬性的屬性
顯示過濾 / 排序結果
有時,我們想要顯示一個數組的過濾或排序副本,而不實際改變或重置原始數據。在這種情況下,可以創建返回過濾或排序數組的計算屬性。
<!-- 取到 numbers 裏面的偶數位的值 -->
<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
})
}
}
在計算屬性不適用的情況下 (例如,在嵌套 v-for 循環中) 你可以使用一個 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 也可以取整數。在這種情況下,它將重複多次模板。
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
輸出HTML
1 2 3 4 5 6 7 8 9 10