講到了v-for和v-bind就不得不提key的這個屬性,主要就是要討論透過v-for所渲染的項目,在資料更新時會怎麼處理,若在v-for渲染的項目中“沒有”加入key屬性(如上面的範例),預設的行為是當數據順序改變時,vue會透過“就地更新(In-place patch)”的策略進行變更,也就是說Vue不會移動任何DOM元素來配合數據順序,只是就地去更新項目內容確保他們在每個索引位置正確的渲染。
透過上述的方式能夠增強網頁的效能,但有時候並沒有辦法達到我們期望的效果,我們透過下面的範例進行說明:
<div id="app">
<h3>Please make your choice:</h3>
<ul>
<li v-for="item in state.names">
{{ item.title }} :
<select>
<option disabled value="" selected>Please select one</option>
<option v-for="(item, index) in state.types" :value="item.value">{{ item.title }}</option>
</select>
</li>
</ul>
<p>
<button @click="sortASC">Sort by Name ASC</button>
<button @click="sortDESC">Sort by Name DESC</button>
</p>
</div>
<script>
const { reactive } = Vue;
const app = {
setup() {
const state = reactive({
names:[
{title: "Vue", value: "Vue"},
{title: "React", value: "React"},
{title: "Angular", value: "Angular"},
{title: "Laravel", value: "Laravel"},
{title: "CakePHP", value: "CakePHP"},
{title: "Django", value: "Django"},
],
types:[
{title: "Frontend", value: "Frontend"},
{title: "Backend", value: "Backend"},
],
})
function sortASC() {
state.names = state.names.sort(function (a, b) {
return a.title > b.title ? 1 : -1;
});
}
function sortDESC() {
state.names = state.names.sort(function (a, b) {
return b.title > a.title ? 1 : -1;
});
}
return { state, sortASC, sortDESC};
}
}
const myVue = Vue.createApp(app).mount("#app");
</script>
大家可以先想像一下這是一個小測驗的網頁,在頁面中有六個選項,選項旁邊有個下拉選單讓使用者挑選正確答案,然後比較重要的是下面有兩個按鈕,可以讓數列按字母重新排序,當使用者選完旁邊的選項之後,再按下重新排序的按鈕,你就會發現,雖然數據重新渲染,但因為沒有更新DOM的順序,所以會發生項目還使用者選取的結果對不起來的問題!
解決方案就是在需要透過v-for渲染的tag中加入key屬性,也就是只要更新上面HTML的第4行如下:
<li v-for="item in state.names" :key="item.title">
就可以得到下面這個範例的結果囉!範例檔
要注意給的key值是不能有重複的,否則頁面會發生錯誤,也不建議使用index當做Key值,因為若爾後插入值在數列中,就會造成渲染錯誤,大家可以依據自己在頁面中的需求,來考量是否需要在v-for中加入key屬性(當然很多人選擇無腦加)。
除了能透過Value來產生數列外,也可以透過以下的方式來取得物件的Key與Index值:
<div id="app">
<ul>
<li v-for="(value, name, index) in state.frameworks">
{{ index + 1 }}. {{ name }} - {{ value }}
</li>
</ul>
</div>
<script>
const { reactive } = Vue;
const app = {
setup() {
const state = reactive({
frameworks: {
Vue: "Frontend",
React: "Frontend",
Angular: "Frontend",
Laravel: "Backend",
CakePHP: "Backend",
Django: "Backend",
},
})
return { state };
}
}
const myVue = Vue.createApp(app).mount("#app");
</script>
好啦!今天的文章就先到這裡,明天繼續跟大家介紹vue中方便又好用的功能。