จากตอนที่แล้วเราติดค้างกันในส่วนของเนื้อหาการใช้งานงาน v-for
directive มาดูกันต่อในเนื้อหาตอนนี้ ใน Vue.js, v-for เป็นคำสั่ง
directive ที่ใช้สำหรับทำ loop (วนลูป) เพื่อแสดงผลรายการของข้อมูล
ที่อยู่ใน array หรือ object ออกมาใน HTML โดยสามารถใช้ได้ใน
template ของ Vue components
ตัวอย่างการใช้ v-for กับ array:
<script setup>
import { ref } from 'vue'
const lists = ref(["One","Two","Three"])
const items = ref([{ message: 'Hello' }, { message: 'World' }])
</script>
<template>
<ul>
<li v-for="item in lists">
{{ item }}
</li>
</ul>
<ul>
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
</template>
ในตัวอย่างข้างต้น:
- lists และ items คือ array ที่เราต้องการวนลูปเพื่อแสดงผล
- item คือตัวแปรที่ใช้สำหรับแทนค่าในแต่ละ iteration หรือ การทำซ้ำ ของ loop
lists จะเป็น array ของข้อมูล string ในขณะที่ items จะเป็น array ของ object
ผลลัพธ์ที่ได้

นอกจากนี้ในการใช้งาน v-for ยังสามารถรองรับการแสดงค่า index ของ แต่ละรายการได้
โดยปกติค่าจะเริ่มต้นที่ 0 โดยกำหนดเป็นค่า option ตัวที่สอง ใน วงเล็บ (item, index)
<ul>
<li v-for="(item, index) in lists">
{{ item }} {{ index }}
</li>
</ul>
<ul>
<li v-for="(item, index) in items">
{{ item.message }} {{ index }}
</li>
</ul>
ผลลัพธ์ที่ได้

เราสามารถใช้รูปแบบการแยกทีละส่วนของตัวของ object เพื่อเข้าถึง property ของ object
นั่นๆ ได้ง่ายและสะดวกขึ้นได้ หรือที่เรียกว่า destructuring เช่น เราต้องการเข้าถึง property
ที่ชื่อว่า message เพื่อให้เรียกใช้งานได้ง่าย ก็จะใช้เป็น { message } in items ทำให้เวลา
เรียกใช้ค่า ก็ไม่ต้องใช้เป็น item.message หรือก็คือเข้าถึงการใช้ข้อมูลได้ง่ายขึ้น
<li v-for="{ message } in items">
{{ message }}
</li>
<!-- หรือเรียกใช้พร้อมกับกำหนด index ก็จะเป็น
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>
กรณีใน array มีลูป array ซ้อนด้านในอีก เราสามารถเรียกใช้ v-for เพื่อลูปรายการข้อมูล
ด้านในซ้อนกันได้ ตัวอย่าง
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
ตัวอย่างการใช้ Vue.js directive v-for ซ้อนกันเพื่อวนลูป (loop) ผ่านข้อมูลที่มี
โครงสร้างแบบ nested (มีรายการภายในรายการ) และแสดงผลข้อมูลเหล่านั้นในรูปแบบ HTML
ดูตัวอย่างโค้ด
<script setup>
import { ref } from 'vue'
const items = ref(
[
{
message: 'Parent 1',
children: ['Child 1.1', 'Child 1.2']
},
{
message: 'Parent 2',
children: ['Child 2.1', 'Child 2.2']
}
]
)
</script>
<template>
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
</template>
ตัวแปร items เป็นข้อมูล array ที่มี object ด้วยกัน 2 รายการ และใน property
ของแต่ละ object ก็จะมี children property ที่เป็น array ซ้อนด้านในอีกที
ผลลัพธ์ที่ได้

ตัวอย่างการใช้ v-for กับ object:
สำหรับข้อมูลประเภท object เราจะใช้ v-for สำหรับวนแสดงข้อมูล property ของ object
ทั้งหมดมาแสดง ดูตัวอย่างด้านล่างประกอบ
<script setup>
import { ref, reactive } from 'vue'
const myObject = reactive({
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
})
</script>
<template>
<ul>
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
</template>
value คือตัวแปร ที่เรากำหนดสำหรับค่าข้อมูลของ property แต่ละตัวเรียงตามลำดับ
ก็จะเป็น title author และ publishedAt หากเราต้องการชื่อ property มาใช้งาน
หรือแสดงด้วย ก็จะเป็น parameter ตัวที่ 2 ก็ให้เรากำหนดค่าเป็น key
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
ผลลัพธ์ที่ได้

นอกจากนั้นยังสามารถใช้ค่า index เป็นค่าตัวที่ 3 เพื่อนำมาใช้งานได้ ดังนี้
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
ผลลัพธ์ที่ได้

การใช้ v-for สำหรับวนลูปตามช่วงตัวเลขหรือ Range
นอกจากเราจะใช้ v-for สำหรับข้อมูล array และ object ที่กล่าวไปแล้วข้างต้น เรายังสามารถใช้
v-for วนลูปค่าช่วงตัวเลข ตั้งแต่ 1 ถึงจำนวนที่ต้องการ (*ต้องเป็นตัวเลขจำนวนเต็ม) สมมติเช่น
เราต้องการวนลูป 10 รายการแรก ก็จะใช้เป็น
<span v-for="n in 10">{{ n }}</span>
ก็จะเป็นการวนแสดงตัวเลข 1 ถึง 10
ผลลัพธ์ทีได้

สังเกตว่า n เป็นตัวแปรหรือชื่อที่เรากำหนดใน for ได้เลย ไม่ต้องทำเป็นค่า state เราสามารถ
ใช้ชื่ออื่นใดๆ ก็ได้ โดยค่าจะเริ่มต้นที่ 1
การใช้ v-for บน <template>
รูปแบบการใช้งานคล้ายกับ v-if ที่อธิบายเพิ่มเติมในตอนที่ผานมา เพียงแต่สำหรับ v-for เป็น
การวนลูปทำซ้ำ ดังนั้น ถ้าเราต้องการคลุมส่วนของเนื้อหา ที่มีหลายๆ รายการ และต้องการ
ให้แสดงซ้ำ ก็สามารถใช้ v-for ร่วมกับ <template> ได้ ตัวอย่าง เช่น
<script setup>
import { ref, reactive } from 'vue'
const items = ref(
[
{ msg: 'Item 1' },
{ msg: 'Item 2' },
{ msg: 'Item 3' }
]
)
</script>
<template>
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
</template>
<style scoped>
.divider {
border-top: 1px solid #ccc; /* เส้นแบ่งสีเทา */
margin: 10px 0;/* ระยะห่างด้านบนและด้านล่าง */
}
</style>
ผลลัพธ์ที่ได้

ข้อดีของการใช้งาน <template> สำหรับ v-for ก็คือ ปกติแล้ว เมื่อมีการใช้งาน v-if และ
v-for จะไม่ใช้ทั้งสองร่วมกัน สมมติเช่น เราไม่ต้องการแสดงรายการที่ต้องทำหรือ todo list
ที่ทำเสร็จแล้ว ดูตัวอย่างประกอบ
<script setup>
import { ref, reactive } from 'vue'
const todos = ref(
[
{ name: 'Buy groceries', isComplete: false },
{ name: 'Read a book', isComplete: true },
{ name: 'Write a blog post', isComplete: false }
]
)
</script>
<template>
<ul>
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
</ul>
</template>
ตัวอย่างโค้ดนี้จะเกิด error เพราะมีการใช้งาน v-if จะมีความสำคัญกว่า v-for จึงไม่สามารถ
ใช้ค่าจาก state ของ v-for ได้ กล่าวคือจะเข้าไปใช้ตัวแปร ที่ประกาศทีหลังไม่ได้ ดังนั้นเพื่อ
ให้ทั้งสองส่วนสามารถใช้ร่วมกันได้ เราจึงใช้ <template> กำหนดวนลูปด้านนอกด้วย v-for
และใช้ v-if ในแท็ก <li> อีกที ก็จะได้เป็น
<script setup>
import { ref, reactive } from 'vue'
const todos = ref(
[
{ name: 'Buy groceries', isComplete: false },
{ name: 'Read a book', isComplete: true },
{ name: 'Write a blog post', isComplete: false }
]
)
const ok = ref(true)
</script>
<template>
<ul>
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
</ul>
</template>
ผลลัพธ์ที่ได้

ก็จะแสดงเฉพาะรายการที่ยังไม่เสร็จเท่านั้น
เนื้อหาตอนนี้จะประมาณนี้ก่อน เรามาดูต่อตอนหน้า เกี่ยวกับการใช้ v-for เพิ่มเติม เมื่อข้อมูล
จำเป็นต้องจัดการ และเกิดการเปลี่ยนแปลงลำดับ และการจัดเรียง รอติดตามตอนหน้า