ในบทความนี้เราจะมาเรียนรู้การวนลูปแสดงข้อมูลในลักษณะ List ซึ่ง Vue ก็มีเครื่องมือมาให้เราใช้งานได้อย่างง่ายดาย ก็คือ v-for มันสามารถใช้งานได้ทั้ง Array และ Object มาดูตัวอย่างแรกกันเลย
v-for กับข้อมูล Array
Template:
1 2 3 4 5 |
<ul id="example-1"> <li v-for="item in items"> {{ item.message }} </li> </ul> |
Data:
1 2 3 4 5 6 |
data: { items: [ { message: 'Foo' }, { message: 'Bar' } ] } |
จะได้ผลลัพธ์
ในตัวอย่างเราจะใช้ v-for="item in items" ลูปแสดงผลข้อมูลที่อยู่ใน items ได้เลย
นอกจากนี้เรายังสามารถดึงค่า index ของข้อมูลในแต่ละ item ออกมาได้โดยเขียนตามตัวอย่างนี้
Template:
1 2 3 4 5 |
<ul id="example-2"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul> |
Data:
1 2 3 4 5 6 7 |
data: { parentMessage: 'Parent', items: [ { message: 'Foo' }, { message: 'Bar' } ] } |
ผลลัพธ์
v-for กับข้อมูล Object
v-for สามารถใช่กับ Object ได้ด้วยเหมือนกัน โดยมีรูปแบบการใช้งานดังตัวอย่างนี้
Template:
1 2 3 4 5 |
<ul id="v-for-object" class="demo"> <li v-for="value in object"> {{ value }} </li> </ul> |
Data:
1 2 3 4 5 6 7 |
data: { object: { firstName: 'John', lastName: 'Doe', age: 30 } } |
ผลลัพธ์
และยังสามารถดึงข้อมูลของ Key ในแต่ละ item ออกมาได้อีกด้วย ดังตัวอย่าง
1 2 3 |
<div v-for="(value, key) in object"> {{ key }}: {{ value }} </div> |
หรือ Index ของแต่ละ key ก็ยังสามารถดึงออกมาได้ ตามนตัวอย่างนี้
1 2 3 |
<div v-for="(value, key, index) in object"> {{ index }}. {{ key }}: {{ value }} </div> |
เรื่องของ Key กับ v-for
เมื่อคุณใช้งาน v-for แล้วเมื่อข้อมูลมีการเปลี่ยนแปลงลําดับใหม่ v-for จะใช้การแทนที่ของข้อมูลแทนการย้าย Dom อาจทําให้ข้อมูลอาจจะแสดงผิดพลาด เช่นข้อมูลแสดงซํ้า สิ่งที่ควรทําคือการกําหนด Key ที่ไม่ซํ้ากัน ให้กับ HTML ในแต่ละ Item เพื่อให้ Vue แยกแยะแต่ละ node ได้
มาดูตัวอย่างการใช้ Key กันครับ
1 2 3 |
<div v-for="item in items" :key="item.id"> <!-- content --> </div> |
Array Change Detection
ในกรณีที่ใช้ v-for กับ Array เราจะมาดูกันว่า การเปลี่ยนแปลงใดบ้างที่จะทําให้ v-for Render Component บ้าง
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
v-for จะไม่ Render component ใหม่ในกรณีดังต่อไปนี้
- แก้ไขข้อมูลในบาง item เช่น items[indexOfItem] = newValue
- เปลี่ยนขนาดของ Array เช่น items.length = newLength
ตามตัวอย่างนี้
1 2 3 4 5 6 7 |
var vm = new Vue({ data: { items: ['a', 'b', 'c'] } }) vm.items[1] = 'x' // is NOT reactive vm.items.length = 2 // is NOT reactive |
แต่เราสามารถทําแบบนี้เพื่อให้ข้อมูลอัพเดทได้
1 2 |
// Vue.set Vue.set(vm.items, indexOfItem, newValue) |
หรือ
1 2 |
// Array.prototype.splice this.items.splice(indexOfItem, 1, newValue) |
หรือ
1 |
this.$set(this.items, indexOfItem, newValue) |
หรือเปลี่ยนขนาดได้โดย
1 |
this.items.splice(newLength) |
Object Change Detection Caveats
ในส่วนของ Object Vue จะไม่ Detect ในกรณีที่เราเพิ่ม Key ของ Object เข้าไปตรงๆ ตามตัวอย่างนี้
1 2 3 4 5 6 7 8 9 |
var vm = new Vue({ data: { a: 1 } }) // `vm.a` is now reactive vm.b = 2 // `vm.b` is NOT reactive |
แต่เรายังสามารถเพิ่มได้ด้วยการใช้ set ตามตัวอย่างนี้
1 2 3 4 5 6 7 |
var vm = new Vue({ data: { userProfile: { name: 'Anika' } } }) |
1 |
Vue.set(vm.userProfile, 'age', 27) |
หรือ
1 |
this.$set(this.userProfile, 'age', 27) |
Displaying Filtered/Sorted Results
ในบางครั้งเราต้องการแสดงผลของ List แบบเรียงลําดับ หรือมีการ Filter ข้อมูล แต่ไม่ต้องการเปลี่ยน Original Data เราสามารถใช้ Computed มาช่วยได้ตามตัวอย่างนี้
Template:
1 |
<li v-for="n in evenNumbers">{{ n }}</li> |
script:
1 2 3 4 5 6 7 8 9 10 |
data: { numbers: [ 1, 2, 3, 4, 5 ] }, computed: { evenNumbers: function () { return this.numbers.filter(function (number) { return number % 2 === 0 }) } } |
v-for with a Range
เราสามารถกําหนดจํานวนการวนลูปแบบนี้ได้ครับ
1 2 3 |
<div> <span v-for="n in 10">{{ n }} </span> </div> |
ผลลัพธ์
v-for with v-if
ถ้าในบางกรณีที่เราต้องการแสดงแค่บาง item เท่านั้น เราสามารถใส่เงื่อนไขเข้าไปได้เช่น
1 2 3 |
<li v-for="todo in todos" v-if="!todo.isComplete"> {{ todo }} </li> |
มาถึงตอนนี้เราสามารถใช้งาน v-for ในรูแปบต่างๆกันไปแล้ว ทั้งในเรื่องของการใช้ v-for กับ Array หรือใช้ กับ Object และเงื่อนไขของการ Update ในแบบต่างๆ หวังว่าเพื่อนๆจะสามารถนําไปประยุกต์ใช้งานได้ไม่ยากครับ