เนื้อหาตอนต่อไปนี้เรามาดูต่อเกี่ยวกับการใช้งาน templates syntax
ซึ่งใน vuesjs นอกจากเราจะใช้รูปแบบการอ้างอิงข้อมูกับจากตัวแปร หรือ property key แล้ว
เรายังสามารถใช้ JavaScript Expressions สำหรับผูกข้อมูลกับ templates ได้
ไฟล์ App.vue
<script setup> import { ref } from 'vue' const number = ref(10) const ok = ref(true) const message = ref('Hello world') const id = ref(2) </script> <template> <div>{{ number + 1 }}</div> <div>{{ ok ? 'YES' : 'NO' }}</div> <div>{{ message.split('').reverse().join('') }}</div> <div :id="`list-${id}`"></div> </template>
ผลลัพธ์ที่ได้
<div>11</div> <div>YES</div> <div>dlrow olleH</div> <div id="list-2"></div>
JavaScript Expressions คืออะไร
JavaScript Expressions (นิพจน์) เป็นชิ้นส่วนของโค้ด JavaScript ที่ทำการคำนวณค่าออกมา
เราสามารถใช้ Expressions เพื่อสร้างค่าใหม่ หรือทำการประมวลผลข้อมูลต่างๆ ในโปรแกรม
JavaScript ได้
นิพจน์ JavaScript สามารถประกอบไปด้วย:
1.ค่าคงที่ (Literals): เช่น เลข, ข้อความ, ตัวแปร, ค่าบูลีน (true/false) เป็นต้น
2.Operators (ตัวดำเนินการ): เช่น +, -, *, / เป็นต้น ที่ใช้สำหรับการดำเนินการทาง
คณิตศาสตร์ หรือการเปรียบเทียบค่า
3.ตัวแปร (Variables): นิพจน์ที่อ้างถึงค่าข้อมูลที่เปลี่ยนแปลงได้
4.Function Calls (การเรียกใช้ฟังก์ชัน): เรียกใช้งานฟังก์ชันเพื่อประมวลผลข้อมูล
ตัวอย่างของ JavaScript Expressions อาจเป็นดังนี้:
* expression คือส่วนที่อยู่หลังเครื่องหมาย =
* ถ้าแต่ละบรรทัดจะเรียกว่า statement หรือคำสั่ง ดังนั้นเราไม่สามารถนำคำสั่ง
ไปแทรกใน template ได้
// ค่าคงที่ const number = 10; const message = "Hello, world!"; const isTrue = true; // ตัวดำเนินการ const sum = 5 + 3; const product = 10 * 2; const isEqual = (5 === 5); // ตัวแปร const x = 20; const y = x * 2; // Function Calls const currentDate = new Date(); const randomNum = Math.random();
ในการเขียนโค้ด JavaScript นิพจน์มักจะถูกนำมาใช้เพื่อสร้างตัวแปร, ประมวลผลข้อมูล,
หรือทำการควบคุมโปรแกรมแบบที่ซับซ้อนขึ้น
ตัวอย่างการนำนิพจน์ ไปแสดงหรือใช้งาน
<div>{{ new Date() }}</div> <div>{{ Math.random() }}</div>
รูปแบบต่อไปนี้ไม่สามารถนำไปใช้งานได้
<!-- เป็นคำสั่ง statement, ไม่ใช่นิพจน์ expression: --> {{ var a = 1 }}
<!-- ใช้รูปแบบ flow control ไม่ได้, ให้ใช้เป็นแบบ ternary expressions (?:) เพื่อกำหนดค่าของ expression ตามเงื่อนไข ที่กำหนดไว้ ในรูปแบบ condition ? expression1 : expression2 แทน --> {{ if (ok) { return message } }}
เราสามารถใช้ JavaScript expressions ทำได้ใน 2 ส่วนดังนี้
1.ในส่วนของการแทรกข้อมูลด้วย {{ }}
2.ใช้ร่วมกับ vue directive ใดๆก็ได้ โดยเฉพาะที่ขึ้นต้นด้วย v-
การเรียกใช้งานฟังก์ชั่น Calling Functions
จากตัวอย่างด้านบน เราจะเห็นว่า การใช้งานฟังก์ชั่น ก็เป็นส่วนหนึ่งของนิพจน์ หรือ expression
เราสามารถนำมาแทรกใน template เพื่อใช้งานได้ ดูตัวอย่างต่อไปนี้
ไฟล์ App.vue
<script setup> import { ref } from 'vue' const date = new Date() function formatDateToThai(date) { const thaiMonths = [ 'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน', 'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม' ]; const thaiDays = ['อาทิตย์', 'จันทร์', 'อังคาร', 'พุธ', 'พฤหัสบดี', 'ศุกร์', 'เสาร์']; const thaiYear = date.getFullYear() + 543; const thaiMonth = thaiMonths[date.getMonth()]; const thaiDayOfWeek = thaiDays[date.getDay()]; const thaiDayOfMonth = date.getDate(); return `${thaiDayOfWeek}, ${thaiDayOfMonth} ${thaiMonth} ${thaiYear}`; } </script> <template> <time :title="formatDateToThai(date)" :datetime="date"> {{ formatDateToThai(date) }} </time> </template>
ผลลัพธ์ที่ได้
<time title="พุธ, 8 พฤษภาคม 2567" datetime="Wed May 08 2024 17:20:17 GMT+0700 (Indochina Time)"> พุธ, 8 พฤษภาคม 2567 </time>
*ข้อควรระวัง สำหรับการใช้งานหรือเรียกใช้ฟังก์ชั่นภายใน template ก็คือ พยายามไม่ใช้ฟังก์ชั่น
ที่มีการเปลี่ยนค่า state อื่นๆ หรือการทำงานในรูปแบบ async ที่มีเวลาที่ต้องรอมาเกี่ยวข้อง ทั้งนี้
ก็เพราะว่า ทุกๆ ครั้งที่ component มีการเรนเดอร์ตัวฟังก์ชั่นที่เราเรียกใช้งานจะทำงานเสมอ ถ้า
state มีการอัปเดทค่าจากฟังก์ชั่น ก็จะวนลูปการทำงานไปเรื่อยๆ ไม่สิ้นสุด ซึ่งจะไม่ทำงาน ในตัวอย่าง จะเป็นเพียง
ฟังก์ชั่นการจัดรูปแบบการแสดงข้อมูลวันที่เท่านั้น
*ข้อจำกัด อีกส่วนของการใช้งาน expressions ใน template ก็คือจะไม่สามารถเรียกใช้งานตัว
แปร Global ได้ เช่น เราไม่สามารถใช้ตัวแปร window เพื่อกำหนดใน expression ได้
<script setup> import { ref } from 'vue' const global_window = window.location </script> <template> <!-- แบบนี้ได้ --> <div>{{ global_window }}</div> <!-- แบบนี้ไม่ได้ <div>{{ window.location }}</div> --> </template>
รูปแบบการใช้งาน Directives
เราได้รู้จักรูปแบบการใช้งาน directive ไปบ้างแล้ว เราจะมาดูภาพรวมเพิ่มเติมกันต่อ โดยทั่วไป
แล้วเราจะกำหนดค่าให้กับ Directive attribute ในแบบนิพจน์เดียวเท่านั้น แต่ก็มีบางตัว เช่น
v-for, v-on และ v-slot ที่อาจจะมีกำหนดมากกว่า 1 ค่า เกี่ยวกับส่วนนี้เราจะได้อธิบายในภาย
หลัง การทำงานหลักๆ ของ directive คือ ทำการอัปเดท DOM หรือ template เมื่อ expression
มีการเปลี่ยนแปลงค่า ดูตัวอย่าง อย่างง่ายเกี่ยวกับ v-if directive
<script setup> import { ref } from 'vue' const seen = ref(false) // หลังจาก 5 วินาที มีการเปลี่ยนแปลงค่า setTimeout(()=>{ seen.value = true; },5000) </script> <template> <p v-if="seen">Now you see me</p> </template>
v-if directive จะทำการเพิ่ม หรือลบ <p> เมื่อตัวแปร seen มีค่าเป็น จริง หรือ เท็จ ตามลำดับ
จะไม่ใช่การซ่อน หรือ แสดงด้วย css แต่เป็นการเพิ่มแท็ก เข้ามา และ การลบแท็กออกไป
จากตัวอย่างโค้ดข้างต้น เมื่อโหลดครั้งแรก จะไม่มีแท็ก <p> ใน DOM แต่หลังจาก 5 วินาที เมื่อค่า
seen มีค่าเป็น true แล้ว แท็ก <p> จะถูกเพิ่มเข้ามา และแสดงผล เราจะเห็นข้อความแสดง
การกำหนด Arguments ใน Directive
Directive บางตัวจะมีการกำหนด อากิวเมนท์ Arguments โดยคั่นด้วยเครื่องหมายโคล่อน เหมือน
ตัวอย่างที่เราได้ใช้งาน v-bind เพื่อกำหนด id attribute ให้กับ html ดูัตัวอย่างเพิ่มเติม สมมติเช่น
เราต้องการกำหนด url ให้กับลิ้งก์แท็ก <a> ก็จะใช้เป็น
<script setup> import { ref } from 'vue' const url = ref('https://www.ninenik.com') </script> <template> <a v-bind:href="url"> Ninenik.com </a> <!-- แบบย่อหรือแบบสั้น --> <a :href="url"> Ninenik.com </a> </template>
href คือตัว อากิวเมนท์ Arguments ที่บอกให้ directive ทำการกำหนด href attribute ของ
element ให้มีค่าเท่ากับ expression หรือตัวแปรที่ต้องการ ในตัวอย่าง url คือค่าที่ต้องการกำหนด
ให้กับ href
ดูเพิ่มเติมตัวอย่างการใช้ v-on ที่เป็น directive สำหรับตรวจจับ event หรือเหตุการณ์ที่เกิดขึ้น
กับ DOM
<script setup> import { ref } from 'vue' const url = ref('https://www.ninenik.com') function doSomething(){ alert('Hello') } </script> <template> <a v-on:click="doSomething" v-bind:href="url"> Ninenik.com </a> <!-- แบบย่อหรือแบบสั้น --> <a @click="doSomething" :href="url"> Ninenik.com </a> </template>
อากิวเมนท์สำหรับ directive v-on จะเป็นชื่อของ event ในตัวอย่างจะเป็น click event และรูป
แบบการเขียนแบบย่อสำหรับ v-on directive จะใช้เป็นตัว @ at sign (แอท ไซน์)
การใช้งาน Dynamic Arguments
นอกจากจะกำหนดค่าอาร์กิวเมนท์แบบตายตัวแล้ว เรายังสามารถกำหนดค่า ที่สามารถเปลี่ยนแปลง
ได้ โดยใช้ [] ปีกกาสี่เหลี่ยมครอบส่วนของตัวแปรข้อมูลที่ใช้เป็นค่าอาร์กิวเมนท์
<script setup> import { ref } from 'vue' const url = ref('https://www.ninenik.com') const attributeName = ref('href') // หลังจาก 5 วินาที มีการเปลี่ยนแปลงค่า setTimeout(()=>{ attributeName.value = 'title' },5000) </script> <template> <a v-bind:[attributeName]="url"> Ninenik.com </a> <!-- แบบย่อหรือแบบสั้น --> <a :[attributeName]="url"> Ninenik.com </a> </template>
เมื่อเริ่มต้น ค่า attribute จะเป็น href ซึ่งเป็น argument ของ directive และหลัง 5 วินาที
มีการเปลี่ยนค่าจาก href เป็น title เนื่องจากเรากำหนดให้ ค่า argument สามารถเปลี่ยนแปลง
ค่าได้โดยใส่ตัวแปรไว้ในปีกกาสี่เหลี่ยม และสำหรับ event เราก็สามารถกำหนดได้ ในรูปแบบเหมือน
กันเช่น
<a v-on:[eventName]="doSomething" > Ninenik.com </a> <!-- แบบย่อหรือแบบสั้น --> <a @[eventName]="doSomething" > Ninenik.com </a>
ข้อจำกัดของค่า Dynamic Argument
จะต้องเป็นข้อมูลประเภทข้อความ String เท่านั้น เว้นแต่ถ้าหากกำหนดค่าเป็น null จะเป็นการลบ
attribute หรือ event ที่มีการผูกกับ DOM ออก อย่างสมมติเช่น เดิมกำหนดอาร์กิวเมนท์สำหรับ
event เป็น click แล้วหลังจาก 5 วินาทีเปลี่ยนค่า null ก็จะเป็นลบ event onclick ออกจาก
DOM นั่นเอง กรณีเราไม่ได้กำหนดอาร์กิวเมนท์เป็นข้อความ ก็จะมี error แจ้งเตือน
ข้อจำกัดของรูปแบบ Dynamic Argument
ในกรณีที่เราต้องการใช้ค่า dynamic argument ที่มีความซับซ้อน สมมติเช่น อย่างกำหนดให้เป็น
data-href เป็นต้น แล้วใช้เป็น
<script setup> import { ref } from 'vue' const url = ref('https://www.ninenik.com') const attributeName = ref('href') </script> <template> <!-- รูปแบบนี้ไม่สามารถใช้งานได้ --> <a v-bind:['data' + attributeName]="url"> Ninenik.com </a> <!-- รูปแบบนี้ไม่สามารถใช้งานได้ แบบย่อหรือแบบสั้น --> <a :['data' + attributeName]="url"> Ninenik.com </a> </template>
รูปแบบข้างต้นจะไม่สามารถใช้งานได้ เนื่องจากมีช่องว่าง ทำให้เกิดรูปแบบ HTML ที่ไม่ถูกต้อง
ดังนั้นกรณีที่ต้องการกำหนดค่าอาร์กิวเมนท์แบบซับซ้อน จะใช้วิธีกำหนดค่า ด้วย computed
<script setup> import { ref, computed } from 'vue' const url = ref('https://www.ninenik.com') const attributeName = ref('href') const attributeName2 = computed(() => { return 'data-' + attributeName.value }) </script> <template> <a v-bind:[attributeName2]="url"> Ninenik.com </a> <!-- แบบย่อหรือแบบสั้น --> <a :[attributeName2]="url"> Ninenik.com </a> </template>
เกี่ยวกับการใช้งานฟังก์ชั่น computed จะได้อธิบายในลำดับภายหลังต่อไป
ในการกำหนดชื่อตัวแปรให้กับค่าอาร์กิวเมนต์ ควรใช้เป็นตัวพิมพ์เล็ก เพื่อป้องกันการอ้างอิงชื่อตัวแปร
ไม่ถูกต้อง เนื่องจากปกติแล้วบราวเซอร์จะแปลงชื่อส่วนใหญ่เป็นตัวพิมพ์เล็ก หากเรากำหนดตัวแปร
โดยมีตัวพิมพ์ใหญ่รวมอยู่ด้วย อาจจะอ้างอิงค่าไม่ถูกต้อง เพราะค่าไม่ตรงกันได้
<!-- ไม่ควรใช้ --> <a :[someAttr]="value"> ... </a> <!-- ควรใช้เป็น --> <a :[someattr]="value"> ... </a>
ส่วนขยายและการปรับแต่ง Modifiers
ในบาง directive ที่บางครั้งรองรับรูปแบบการทำงานเฉพาะ เราสามารถรูปแบบการใช้งานที่ปรับ
เฉพาะนั้นๆ ได้โดยต่อท้าย . (จุด) ตัวอย่างเช่น การใช้งาน .prevent Modifiers เพื่อบอกให้
v-on directive เรียกใช้งาน event.preventDefault() ได้ ดูตัวอย่าง
<script setup> import { ref } from 'vue' const url = ref('https://www.ninenik.com') function doSomething(){ alert('Hello') } </script> <template> <a v-on:click.prevent="doSomething" v-bind:href="url"> Ninenik.com </a> <!-- แบบย่อหรือแบบสั้น --> <a @click.prevent="doSomething" :href="url"> Ninenik.com </a> </template>
จากตัวอย่างโค้ดข้างต้น ปกติเมื่อเราคลิกที่ลิ้งค์ ก็จะเรียกใช้ฟังก์ชั่น doSomething() และทำการ
alert ข้อความว่า Hello จากนั้นก็จะลิ้งค์ไปยัง url ที่เรากำหนด แต่เมื่อเรากำหนดส่วนของ
.prevent Modifiers เข้าไป ก็เหมือนกับเรียกใช้งาน event.preventDefault() คือไม่มีการ
ลิ้งค์ไปยัง url ตามปกตินั่นเอง
สำหรับเนื้อหาในตอนนี้เราได้รู้จัก directive เพิ่มเติม ทั้งข้อจำกัด รูปแบบการใช้งาน รวมถึงการ
ใช้งานร่วมกับ JavaScript Expression สำหรับตอนหน้าจะเป็นอะไร รอติดตาม