v-for
就是 JavaScript 裡的迴圈,基於一組資料來製作相同元素區塊。
先簡單講一下 JavaScript 裡 for...in
、 for...of
的使用方法及差別。
for...in
主要是為遍歷物件屬性。
const obj = {a:1, b:2, c:3}
for(const prop in obj){
// prop 是物件屬性名
console.log(prop) //a b c
console.log(obj[prop]) // 1 2 3
}
for...of
用於可迭代物件,如字串、陣列、DOM NodeList 等等。
const arr = ['a', 'b', 'c']
for(const value of arr){
// value 是陣列值
console.log(value) //a b c
}
v-for
指令僅有值
<!--item是從items代入的資料(從索引值0開始一筆一筆的代入)-->
<div v-for="item in items">{{ item.type }}</div>
放入索引值
<!--item是從items代入的資料(從索引值0開始一筆一筆的代入),index是代入資料(item)的索引值-->
<div v-for="(item,index) in items">{{ index }}-{{ item.type }}</div>
整體架構會如下:
<div id="vm">
<div v-for="(item,index) in items">{{ index }}-{{ item.type }}</div>
</div>
<script>
const vm = new Vue({
el:'#vm',
data:{
items:[{type: 'apple', made: 'USA'},{type: 'oppo', made: 'China'}]
}
})
</script>
對於陣列資料的渲染,更推薦使用 v-for="item of items"
,因為在 JS 中 for...of
比 for...in
更適合用在迭代中,因此使用 v-for="item of items"
會更接近 JS 的語法。
<!--value是物件屬性值,key是物件屬性名,而index是指該key-value pair 是第幾筆資料-->
<div v-for="(value,key,index) in obj">{{ key }}-{{ value }}</div>
渲染出來的結果跟迭代陣列很像。
v-for
指令來迭代數字<div v-for="num in 10">{{ num }}</div>
須注意 num
的值是從 1 開始。
v-for
元素複用v-for
跟 v-if
有相同的問題, Vue 為了更快速的渲染畫面,在資料改變的狀況下,不會移動已經被渲染過的 DOM ,而是直接更新資料(把已經存在的 DOM 元素資料修改成新的值)。
所以可以透過在 HTML 中使用 v-for
的元素加入 key
Attribute(值須為唯一,類似 id
),通知 Vue 這個部分資料如果改變,對於已經存在的元素是需要重新排序或是重用一個元素的。
<!--有key Attribute-->
<div v-for="(user,index) of users">
<label>{{user.label}}</label>
<input :placeholder="user.placeholder" :key="user.label">
</div>
可以參考 Demo :[DAY07]跟 Vue.js 認識的30天 - Vue 的列表渲染 比較差別。
當需要一個經過濾後的陣列去渲染時,可以創建 computed
去執行過濾,再透過 v-for
渲染對 computed
執行結果去做渲染。
<!--對oddNums的值做渲染-->
<div v-for="odd in oddNums">{{ odd }}</div>
<script>
const vm = new Vue({
el:'#vm',
data:{
numbers: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
},
computed:{
oddNums(){
// 返回 [1, 3, 5, 7, 9]
return this.numbers.filter(num => num%2 === 1)
}
}
})
</script>
template
為 v-for
做分組使用到現在,覺得 template
做分組的最大好處真的是減少 <div>
標籤的出現。
<template v-for="item in items">
<h3>{{ item.type }}</h3>
<p>{{ item.made }}</p>
</template>
在 Vue 文件中有說明,只有 push()
、 pop()
、 shift()
、 unshift()
、 splice()
、 sort()
、 reverse()
等 Vue 會知道陣列有變動。
所以當使用 array[index]
執行更新時,是沒辦法觸發頁面更新的。
const vm = new Vue({
el:'#vm',
data:{
numbers: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
},
methods:{
changeNum(){
// 網頁不會更新
this.numbers[2] = 13
this.numbers[10] = 11
// 網頁會更新
// this.numbers.splice(2,1,13)
// this.numbers.push(11)
// this.numbers = [...this.numbers,11]
}
}
})
v-for
及 v-if
不要同時出現在同一個元素上在 Vue 執行的過程中, v-for
的層級較高,所以會在執行完 v-for
才去執行 v-if
的判斷,也因此會造成 v-for
跑完後,才去一個一個執行判斷,之後決定不執行,這是非常多此一舉的。
如果真的需要 v-for
及 v-if
一起使用的話,建議可以在 v-for
外層(可以是 template
)元素上加上 v-if
,先跑完判斷,再決定是否要迭代。
<!--當show是truthy時,下面迭代才會執行-->
<template v-if="show">
<div v-for="item in items">
<h3>{{ item.type }}</h3>
<p>{{ item.made }}</p>
</div>
</template>
<!--不建議使用下面的做法-->
<!--會先跑迭代,才執行判斷-->
<div v-for="item in items" v-if="show">
<h3>{{ item.type }}</h3>
<p>{{ item.made }}</p>
</div>
Demo:[DAY07]跟 Vue.js 認識的30天 - Vue 的列表渲染
參考資料:
Vue.js - v-for