1. 陣列與物件 v-for 的索引不同
v-for 使用在陣列與物件上,會有哪些差異呢?
- 使用於陣列上 → 索引 (key) 為 0, 1, 2
<li v-for="(item, key) in arrayData">
{{ key }} - {{ item.name }} {{ item.age }} 歲
</li>
- 使用於物件上 → 索引 (key) 為物件的屬性
<li v-for="(item, key) in objectData">
{{ key }} - {{ item.name }} {{ item.age }} 歲
</li>
2. 就地更新(快速置換)
先在 <input>
上按照順序輸入 1 2 3,接著按下按鈕反轉陣列,發現 1 2 3 的順序沒有改變,為什麼呢?
<li v-for="(item, key) in arrayData">
{{ key }} - {{ item.name }} {{ item.age }} 歲
<input type="text" />
</li>
<button class="btn" @click="reverseArray">反轉陣列</button>
// methods 裡的 reverseArray
reverseArray: function () {
this.arrayData.reverse();
console.log(this.arrayData);
},
情況如下圖,到底是什麼原因,讓我們執行反轉陣列後,三個 Input 的順序卻沒有跟著反轉呢?
原因是因為 Vue 替換 DOM(文件物件模型)元素是使用就地更新(快速置換)的方式。
原理解釋
當 Vue 正在更新使用 v-for
渲染的元素列表時,它默認會使用就地更新的策略。
在就地更新的狀況下,當資料的順序被改變,Vue 不會因應資料順序而移動 DOM 元素,而是會就地更新每個元素的內容,並且確保它們在每個索引位置上正確渲染。
如果不想就地更新,希望要達到反轉,那我們需要給 Vue 提示,讓它能追蹤每個節點的身份,才能既重複使用,又正確地重新排序元素,而這個提示就是為每一項元素加上唯一的 key 值。
加上理想的 key 值
- 使用
:key
是為了避免就地複用(快速替換),我們想要直接做強制替換 - 理想的 key 值是每項都有的唯一 ID,重複值是不能用來作為 key 的
在這個例子中,使用 item.age
與 item.name
作為 key 都是可以的,但是不能用 key(也就是 :key = "key"
)。
為什麼不行?這邊 key 不是剛好分別是 0, 1, 2 嗎?
這是因為如果用 key 當作唯一值,則在反轉前與反轉後,這些 key 在順序上依然都是 0, 1, 2,而不是變成 2, 1, 0,結果就會變成就地更新的情況了。
所以撰寫的時候,如果有唯一的 ID 的值可以使用,就盡量不要使用 index 這種索引值。
最後提醒一點,官方建議使用 v-for 都綁定 key 喔
3. 過濾(Filter)
使用 v-for
的時候,常常會使用到過濾。
例如:針對上方輸入的文字 (filterText),過濾出下方的內容 (filterArray)
<input type="text" v-model="filterText" @keyup.enter="filterData" />
<ul>
<li v-for="(item, key) in filterArray" :key="item.age">
{{ key }} - {{ item.name }} {{ item.age }} 歲 <input type="text" />
</li>
</ul>
這裡的
filterArray
是一個空陣列
// methods 裡的 filterData
filterData: function () {
var vm = this; // 這個 this 指向 Vue 應用程式
vm.filterArray = vm.arrayData.filter(function (item) {
console.log(vm.filterText, item.name, item.name.match(vm.filterText));
return item.name.match(vm.filterText);
});
},
match() 說明
match()
主要用途是核對字串是否相符。
(這裡是拿 item.name
與 vm.filterText
比較是否相符)
Array.prototype.filter() 說明
filter()
跟 forEach()
很像,都是用來處理陣列資料,會將陣列內的每個元素一個個傳入並執行給定的函式一次。
然而 filter()
多了一個 return。
return 後面的內容是 true 的話,便會回傳「陣列內的 單個元素」到指定的變數內。
此段說明參考 JavaScript 陣列處理方法:
filter() 會回傳一個陣列,其條件是 return 後方為 true 的物件,很適合用在搜尋符合條件的資料。
在這個例子中:
這裡的 item 代表 arrayData 內的每一個元素(e.g.{name: '小明', age: 16}
)
使用 match() 比較 item.name
與 vm.filterText
是否相符,
相符便回傳 arrayData 內的單個元素(e.g.{name: '小明', age: 16}
)到變數 filterData 內。
4. 不能運行的狀況
設長度為零
在原本的 JavaScript 裡,如果把陣列長度改成 0 的話,可以清空陣列。
// methods 裡的 cantWork
cantWork: function () {
this.arrayData.length = 0;
console.log(this.arrayData);
}
但是在 Vue 裡面,這樣的操作是沒有用的。
雖然 arrayData 的長度確實會被改成零,但資料還是存在。
直接操作陣列
直接指定陣列裡的第 0 個物件並修改資料,雖然在 console 與 Vue 開發者工具中會看到更改,但是畫面資料卻沒有跟著變動。
// methods 裡的 cantWork
cantWork: function () {
this.arrayData[0] = {
name: '小強',
age: 99,
}
console.log(this.arrayData);
}
在 Vue 中,如果要操作陣列裡的內容,不能透過索引去操作它。
我們必須使用 Vue.set()
解法:Vue.set(target, key, value)
想要操作或新增「原本沒有在 data 裡的資料」時,需要使用 Vue.set(針對目標, 索引, 值)
強制將資料寫入 data。
// methods 裡的 cantWork
cantWork: function () {
Vue.set(this.arrayData, 0, {
name: '阿強',
age: 99
});
console.log(this.arrayData);
}
5. 純數字的迴圈
除了使用陣列或物件,也可以使用純數字的迴圈。
<ul>
<li v-for="item in 10">
{{ item }}
</li>
</ul>
使用 v-for="item in 一個數值"
,數值是多少,迴圈就會跑幾次。
6. 在 Template 上運用 v-for
如果需要同時使用 v-for
與 v-if
的話,可以藉由在 <template>
標籤上使用 v-for
,唯一值 key
綁定在內部元素上的方式。
注意!雖然在官方文件的範例 v-for on a template 當中並沒有綁定 key
,但我認為還是應該加上 key
,目的是讓 Vue 在演算上能夠區分出元素的唯一性,因此我一樣會做綁定 key
的動作。
<ul>
<template v-for="item in items">
<li :key="item.uid" v-if="true">{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
7. v-for 與 v-if 混合使用
使用 v-if
對 v-for
加入年齡限制,改變畫面上呈現的結果。
<ul>
<li v-for="(item, key) in arrayData" v-if="item.age<=20">
{{ key }} - {{ item.name }} {{ item.age }} 歲
</li>
</ul>
8. v-for 與元件
這邊簡單介紹元件與 v-for 的運用,之後會再詳細介紹元件。
因為現在建議元件使用 v-for 都加上 key,
所以我們想要在元件 list-item
上加入剛才講到的 key 的話,
我們要先定義好元件,接著再加上唯一的值 (ID) 當作 key。
這邊使用的 item.age
就是唯一的值。
<list-item
:item="item"
v-for="(item, key) in arrayData"
:key="item.age"
></list-item>
Vue.component('list-item', {
template: `
<li>
{{ item.name }} {{ item.age }} 歲
</li>
`,
props: ['item'],
});
以上資源是我自己整理過後的筆記,若有錯誤歡迎隨時和我聯繫