Vue-101-Day 9
25 May 2019 |使用v-for
這個 directive 將 Array/Object 裡的內容對應成 HTML 元素
對 Array 使用 v-for
<div id="app-10">
<h1 v-for="item in items">{{ item.message }}</h1>
</div>
var vm10 = new Vue({
el: '#app-10',
data: {
items: [{ message: 'Hello' }, { message: 'Hola' }]
}
})
有時候可能會需要知道目前 index 到哪裡,Vue 在第二個參數(可選填)上,提供目前的 index
<div id="app-10">
<h1 v-for="(item, index) in items">{{ index }} - {{ item.message }}</h1>
</div>
除了 in 的用法,也可以使用 of 的寫法達成同樣效果
<div id="app-10">
<h1 v-for="(item, index) of items">{{ index }} - {{ item.message }}</h1>
</div>
對 Object 使用 v-for
<div id="app-11">
<h1 v-for="value of object">{{ value }}</h1>
</div>
var vm11 = new Vue({
el: '#app-11',
data: {
object: {
title: 'coding diary',
author: 'David',
publishedAt: '2019-01-01'
}
}
})
結果
coding diary
David
2019-01-01
在 Object 使用也可以選擇性參數,不過順序及意義會不太一樣。
以下範例來看
- 第一個(即 name):object 的屬性名稱
- 第二個 (即 index):目前項目 index
<div id="app-11">
<h1 v-for="(value, name, index) of object">
{{ index }} - {{ name }} - {{ value }}
</h1>
</div>
結果
0 - title - coding diary
1 - author - David
2 - publishedAt - 2019-01-01
維護狀態
Vue 渲染更新的 List 元素,預設會重複使用已經渲染好的元素
<div id="app-12">
<h1 v-for="(item, index) of items">
<input type="text" :placeholder="item.name" />
</h1>
</div>
var vm12 = new Vue({
el: '#app-12',
data: {
items: [
{ id: '1', name: '選項 1' },
{ id: '2', name: '選項 2' },
{ id: '3', name: '選項 3' },
{ id: '4', name: '選項 4' }
]
}
})
當改變元素順序時,會發現 input 已經填寫的內容並沒有跟著改變
這時候可以加上 key
,確保每個元素都是唯一值
,讓元素更新時可以重複渲染
<div id="app-12">
<h1 v-for="(item, index) of items">
<input type="text" :placeholder="item.name" :key="item.id" />
</h1>
</div>
Mutation Methods
以下方法會觸發 View 的更新
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
更新 Array 資料範例
vm12.items = vm12.items.filter(el => el.id % 2 === 0)
注意事項
直接以下方法,並不會觸發 View 上的更新
- 直接設定 index 上的值, e.g:vm12.items[index] = ‘Hi’
- 更新 array 的長度, e.g:vm12.items.length = 1
範例:
<div id="app-13">
<h1 v-for="(item, index) of items">{{ index }} - {{ item }}</h1>
</div>
var vm13 = new Vue({
el: '#app-13',
data: {
items: [1, 2, 3, 4]
}
})
這時候要把值更新到 View 上可以使用 Vue.set
,來達成目的
Vue.set(vm13.items, 0, 'Hi~~~~~')
假使 length 只有 4,直接設定Vue.set(vm13.items, 5, 'Hi~~~~~')
,vm13.items[4]值會為 undefined
0 - 1
1 - 2
2 - 3
3 - 4
4 -
5 - Hi~~~~~
註:也可以使用vm.$set
,它是 Vue.set 的 global alias
在 Object 也是同樣道理,設定vm14.profile.age = 18
,也並不會更新到畫面,使用Vue.set(object, propertyName, value)
將值更新到畫面
<div id="app-14">
<h1 v-for="(value, name, index) in profile">{{ name }} - {{ value }}</h1>
</div>
Vue.set(vm14.profile, 'age', 18)
但要同時設定多個屬性值
,使用 Vue.set 就顯得不方便,要寫很多程式碼,這時候可以使用Object.assign()達成同時設定多個屬性值
vm14.profile = Object.assign({}, vm14.profile, {
age: 27,
favoriteColor: 'Vue Green'
})
顯示過濾條件及排序後的結果
以下範例中,要顯示偶數
<div id="app-13">
<h1 v-for="number of evenNumbers">{{ number }}</h1>
</div>
var vm13 = new Vue({
el: '#app-13',
data: {
numbers: [1, 2, 3, 4, 5]
},
computed: {
evenNumbers: function() {
return this.numbers.filter(function(el) {
return el % 2 === 0
})
}
}
})
但有些時候,使用 computed 方法是不可行的 (e.g. inside nested v-for loops),此時可以使用 methods
代替
<div id="app-13">
<h1 v-for="number of evenNumbers(numbers)">{{ number }}</h1>
</div>
var vm13 = new Vue({
el: '#app-13',
data: {
numbers: [1, 2, 3, 4, 5]
},
methods: {
evenNumbers: function() {
return this.numbers.filter(function(el) {
return el % 2 === 0
})
}
}
})
使用 v-for 建立一個範圍內的值
<div id="app-15">
<span v-for="n in 10"> {{ n }}</span>
</div>
1 2 3 4 5 6 7 8 9 10
在 template 使用 v-for
<div id="app-15">
<template v-for="n in 10">
<li>{{ n }}</li>
</template>
</div>
同時使用 v-for 及 v-if
在同一個 element 上,v-for的優先權 大於 v-if
,也就是 loop 跑 10 次,v-if 也會跑 10 次
<div id="app-16">
<li v-for="todo in todos" v-if="todo.isCompleted">
Completed: {{ todo.task }}
</li>
</div>
var vm16 = new Vue({
el: '#app-16',
data: {
todos: [
{ task: 'do homework', isCompleted: true },
{ task: 'do chores', isCompleted: false }
]
}
})
特殊情況
若同時出現 v-for、v-if、v-else,且陣列內容長度為 0
範例程式
<div id="app-16">
<li v-for="todo in todos" v-if="todo.length !== 0">
Completed: {{ todo.task }}
</li>
<li v-else>nothing to show</li>
</div>
預期結果應該是 nothing to show,可是輸出結果卻沒有該內容,因為v-for 優先權大於 v-if,當為空陣列,v-for迭代沒有資料,也就不會執行v-if
解決方法
v-if 額外拉出來判斷長度為 0 時的結果
<div id="app-16">
<li v-for="todo in todos">Completed: {{ todo.task }}</li>
<li v-if="todos.length === 0">nothing to show</li>
</div>
參考資料:
Comments