เนื้อหาตอนนี้เรามาดูเกี่ยวกับการจัดการ event ใน vuejs ซึ่งเราได้
คุ้นตัวอย่างการใช้งานเบื้องต้นมาบ้างแล้ว แต่จะมาดูรายละเอียดเพิ่มเติม
เราทราบดีว่าปกติจะใช้ v-on directive หรือเขียนแบบสั้นใช้เป็น @ แล้ว
ตามด้วย event ที่ต้องการกำหนด เพื่อใช้สำหรับตรวจจับหรือคอยสังเกต
เหตุการ์หรือ event ที่เกิดขึ้นกับ DOM แล้วให้ทำงานคำสั่งบางอย่างตามต้องการ
เมื่อเกิด event น้้นๆ ขึ้น ตัวอย่างรูปแบบการใช้งาน
v-on:click="handler" หรือเขียนแบบย่อเป็น @click="handler"
Event Handling คืออะไร
Event Handling หรือการจัดการเหตุการณ์ คือกระบวนการที่ระบบซอฟต์แวร์ตอบสนองต่อ
เหตุการณ์ที่เกิดขึ้นจากการกระทำของผู้ใช้หรือเหตุการณ์ที่เกิดขึ้นในระบบเอง เช่น การคลิกเมาส์,
การกดแป้นพิมพ์, การเปลี่ยนแปลงค่าของฟอร์ม หรือเหตุการณ์ที่เกิดขึ้นจากการโหลดข้อมูลเสร็จ
สมบูรณ์ เป็นต้น
การทำงานของ Event Handling
1.Event Creation: เหตุการณ์ถูกสร้างขึ้นเมื่อผู้ใช้ทำการกระทำบางอย่างหรือเมื่อระบบเกิด
เหตุการณ์บางอย่าง เช่น ผู้ใช้คลิกปุ่ม, เลื่อนเมาส์, กดคีย์, หรือระบบมีการเปลี่ยนแปลงบางอย่าง
2.Event Detection: ระบบหรือโปรแกรมตรวจจับเหตุการณ์ที่เกิดขึ้น
3.Event Handling: ระบบหรือโปรแกรมดำเนินการบางอย่างเพื่อตอบสนองต่อเหตุการณ์
ที่ตรวจจับได้
ประเภทของเหตุการณ์บางส่วน
1.เหตุการณ์จากผู้ใช้ (User Events):
click: เมื่อผู้ใช้คลิกที่องค์ประกอบ
dblclick: เมื่อผู้ใช้ดับเบิลคลิกที่องค์ประกอบ
keydown, keyup, keypress: เมื่อผู้ใช้กดหรือปล่อยแป้นพิมพ์
mouseover, mouseout: เมื่อผู้ใช้เลื่อนเมาส์เข้าไปหรือออกจากองค์ประกอบ
submit: เมื่อผู้ใช้ส่งฟอร์ม
2.เหตุการณ์จากระบบ (System Events):
load: เมื่อหน้าเว็บหรือทรัพยากรถูกโหลดเสร็จสิ้น
resize: เมื่อหน้าต่างเบราว์เซอร์ถูกปรับขนาด
scroll: เมื่อหน้าเว็บถูกเลื่อน
ใน Vue.js, การจัดการเหตุการณ์ทำได้ง่ายขึ้นด้วย directive ที่เรียกว่า v-on หรือย่อเป็น @
เราสามารถจัดการกับ การทำงานของฟังก์ชั่น หรือ handle ในสองรูปแบบคือ
ใช้ method handlers หรือ inline handlers โดยมีความแตกต่างและข้อดีข้อเสีย
ของแต่ละวิธีดังนี้:
Inline Handlers
Inline handlers คือการเขียนโค้ดจัดการเหตุการณ์โดยตรงใน template ภายใน
directive เช่น v-on
<script setup> import { ref } from 'vue' </script> <template> <button @click="console.log('Button clicked!')">Click me</button> </template>
ข้อดี:
- ง่ายและรวดเร็วในการเขียน โดยเฉพาะในกรณีที่ logic ของเหตุการณ์นั้นมีขนาดเล็กและ
ไม่ซับซ้อน
- ไม่ต้องประกาศ method เพิ่มเติมใน script
ข้อเสีย:
- โค้ดอาจจะยากต่อการอ่านและบำรุงรักษาถ้า logic ซับซ้อนขึ้น
- ไม่สามารถนำโค้ดกลับมาใช้ใหม่ได้อย่างสะดวก
- การทดสอบโค้ดที่อยู่ใน inline handler จะทำได้ยากกว่า
Method Handlers
Method handlers คือการสร้าง method ในส่วนของ methods ภายใน Vue instance
หรือ component จากนั้นใช้ชื่อ method นี้ใน directive เช่น v-on (หรือย่อเป็น @)
<script setup> import { ref } from 'vue' function handleClick() { alert('Button clicked!'); } </script> <template> <button @click="handleClick">Click me</button> </template>
ข้อดี:
- โค้ดมีการจัดระเบียบดีขึ้น ทำให้ง่ายต่อการอ่านและบำรุงรักษา
- Method สามารถนำกลับมาใช้ได้หลายครั้งในหลาย ๆ ส่วนของ component
- สามารถทดสอบ method ได้ง่ายขึ้นเพราะแยกออกมาจากส่วน template
ข้อเสีย:
- ต้องเขียนโค้ดมากขึ้นเล็กน้อยเนื่องจากต้องประกาศ method ใน script
การเรียกใช้งาน Method ในรูปแบบ Inline
ในบางครั้งหรือบางโอกาส เราอาจจะต้องการส่งข้อมูลเข้าไปใน method หรือฟังก์ชั่นเพื่อใช้งาน
โดยกำหนดผ่าน inline เพื่อให้สะดวกต่อการเรียกใช้ โดยเฉพาะถ้าจำเป็นต้องมีการส่งค่าเข้าไป
เราก็สามารถทำได้ดังนี้
<script setup> import { ref } from 'vue' function say(message) { alert(message) } </script> <template> <button @click="say('hello')">Say hello</button> <button @click="say('bye')">Say bye</button> </template>
ดูตัวอย่างท้ายบทความ
การจัดการ DOM event ใน method หรือฟังก์ชั่น
ปกติเมื่อเราสร้างชื่อ method และกำหนดการทำงาน ไม่มีการส่งค่าใดๆ เข้าไปใช้งาน ก็มักจะไม่
กำหนด parameter เช่น อาจจะใช้เป็น handleClick() แต่กรณีที่เราอาจจะไม่ต้องการส่งค่าใดๆ
เข้าไปแต่อาจจะต้องการใช้งาน event ที่เกิดขึ้น ซึ่งตัวแปร event นี้จะเป็น native DOM event
ที่เราสามารถใช้งานฟังก์ชั่นต่างๆ ของ javascript ได้เลย โดยเมื่อต้องการใช้งาน ก็สามารถกำหนด
ค่าเป็น handleClick(event) ดูตัวอย่างโค้ดด้านล่าง
<script setup> import { ref } from 'vue' const name = ref('VueJS') // กำหนด event เป็น parameter สำหรับใช้งาน event ที่ถูกเรียก function greet(event) { alert(`Hello ${name.value}!`) // `event` คือ native DOM event if (event) { // แสดงข้อความแจ้งว่า เกิด event ขึ้นกับ tag ชื่อว่าอะไร alert(event.target.tagName) } } </script> <template> <button @click="greet">Greet</button> </template>
สังเกตว่าวิธีนี้ ในขั้นตอนการเรียกใช้งาน เราจะกำหนดแค่ชื่อ method ในตัวอย่างคือ greet
ไม่มีการส่งค่า event หรือค่าใดๆ เข้าไป
การจัดการ DOM event ในรูปแบบ Inline
ในกรณีที่เราอาจจะต้องมีการส่งค่า parameter อื่นเข้าไป พร้อมทั้งใช้งาน event ด้วย เราสามารถ
เรียกใช้งาน event แบบ inline ในรูปแบบดังนี้ ได้
- ใช้ตัวแปรเฉพาะ ที่ชื่อว่า $event ส่งเข้าไป
- ใช้รูปแบบ arrow ฟังก์ชั่น ส่ง event เข้าไปก็ได้
<script setup> import { ref } from 'vue' function warn(message, event) { // เราสามารถจัดการกับ event ตามต้องการใน method นี้ได้ if (event) { event.preventDefault() } alert(message) } </script> <template> <!-- ใช้งาน $event special variable --> <button @click="warn('Form cannot be submitted yet.', $event)"> Submit </button> <!-- ใช้งาน inline arrow function --> <button @click="(event) => warn('Form cannot be submitted yet.', event)"> Submit </button> </template>
การปรับแต่ง Event (Event Modifiers) คืออะไร
ใน Vue.js, Event Modifiers เป็นเครื่องมือที่ใช้ร่วมกับ event directives (v-on หรือ @)
เพื่อปรับแต่งพฤติกรรมของเหตุการณ์ที่ถูกจัดการ โดย Event Modifiers สามารถช่วยลดโค้ดที่
ต้องเขียนและทำให้โค้ดอ่านง่ายขึ้น รวมถึงลดข้อผิดพลาดที่อาจเกิดขึ้นได้
โดยปกติเราจะเคยเห็นการใช้งาน event.preventDefault() หรือ event.stopPropagation()
ในส่วนของการจัดการ event อย่างเช่น กดลิ้งค์ แต่ยังไม่ต้องลิ้งค์ไป url ที่กำหนด ให้ทำคำสังอื่นก่อน
ก็จะเห็นการใช้งาน event.preventDefault() แบบนี้เป็นต้น
ใน vue.js จะใช้วิธีการกำหนดด้วย ต่อท้ายชื่อ event ด้วย . (จุด) แล้วตามด้วยชื่อการปรับแต่ง ซึ่ง
ได้แก่ค่าต่างๆ ดังนี้
ประเภทของ Event Modifiers ใน Vue.js
- .stop - หยุดการแพร่กระจายของเหตุการณ์ (event propagation)
- .prevent - ยกเลิกการทำงานค่าเริ่มต้นของเหตุการณ์ (prevent default behavior)
- .capture - ใช้ capture mode แทน bubbling mode สำหรับการจัดการเหตุการณ์
- .self - จัดการเหตุการณ์เฉพาะเมื่อถูก trigger โดย element เอง (ไม่ใช่จาก descendant)
- .once - จัดการเหตุการณ์เพียงครั้งเดียวและจะถูกลบออกหลังจากการเรียกใช้ครั้งแรก
- .passive - ระบุว่า event listener จะไม่เรียก preventDefault (ใช้เพื่อเพิ่ม
performance ในบางกรณี)
ตัวอย่างพื้นฐานของการใช้ .stop
การใช้ .stop modifier ใน Vue.js เป็นวิธีที่มีประสิทธิภาพในการหยุดการแพร่กระจายของ
เหตุการณ์ (event propagation) เพื่อให้แน่ใจว่าเหตุการณ์นั้นจะไม่ถูกส่งต่อไปยังองค์ประกอบ
แม่(parent) (ancestor elements) ใน DOM tree
<script setup> import { ref } from 'vue' function handleParentClick() { alert('Parent element clicked') } function handleButtonClick() { alert('Button clicked') } </script> <template> <div @click="handleParentClick"> Parent Element <button @click.stop="handleButtonClick">Click me</button> </div> </template>
ปกติ ถ้าไม่กำหนด .stop ให้กับปุ่ม ถ้าเรากดที่ปุ่ม ที่อยู่ใน div ที่เป็น parent จะทำคำสั่ง
ทั้ง handleButtonClick และ handleParentClick แต่เมื่อเรากำหนด .stop ให้กับปุ่ม
จะทำให้ event ไม่แพร่ไปยัง div ที่เป็น parent จึงเรียกแค่ handleButtonClick ทำงาน
ตัวอย่างพื้นฐานของการใช้ .prevent
การใช้ .prevent modifier ใน Vue.js เป็นวิธีที่มีประสิทธิภาพในการยกเลิกการทำงานค่า
เริ่มต้นของเหตุการณ์ (prevent default behavior) เช่น การส่งฟอร์ม, การคลิกลิงก์,
หรือการทำงานอื่น ๆ ที่เบราว์เซอร์จัดการโดยค่าเริ่มต้น
<script setup> import { ref } from 'vue' const name = ref('') function handleSubmit() { alert('Form submitted with name: ' + name.value) } function handleLinkClick(){ alert('Hello World!') } </script> <template> <form @submit.prevent="handleSubmit"> <input type="text" v-model="name" placeholder="Enter your name"> <button type="submit">Submit</button> </form> <a href="https://www.ninenik.com" @click.prevent="handleLinkClick"> Go to Ninenik.com </a> </template>
ตัวอย่างของฟอร์ม และ ลิ้งค์ ปกติถ้าเป็น form ถ้าเรากดส่งข้อมูล ก็จะทำการส่งข้อมูลในฟอร์ม
ไปยังไฟล์จัดการข้อมูลตามต้องการ หรือกรณีลิ้งค์ เมื่อเราคลิกที่ลิ้งค์ก็จะไปยังหน้าเว็บไซต์หรือ
ลิ้งค์นั้นๆ แต่ในตัวอย่าง เมื่อเรากำหนดค่าการปรับแต่ง event เข้าไป ก็จะทำให้ การทำงานที่
เป็นค่าเริ่มต้น ไม่ทำงาน นั่นคือ ฟอร์มไม่ส่งข้อมูล แต่ทำฟังก์ชั่น handleSubmit และลิ้งค์ก็
ไม่ลิ้งค์ไปยังเว็บไซต์ แต่ทำงานฟังก์ชั่น handleLinkClick
ตัวอย่างพื้นฐานของการใช้ .capture
การใช้ .capture modifier ใน Vue.js ช่วยให้เราสามารถจัดการเหตุการณ์ในช่วงแคปเจอริ่งเฟส (capturing phase)
แทนที่จะเป็นช่วงการบับบลิ้งเฟส (bubbling phase)
โดยปกติแล้ว, เหตุการณ์ในเบราว์เซอร์จะถูกส่งผ่านจากองค์ประกอบเป้าหมายขึ้นไปยังองค์ประกอบ
แม่(parent) แต่การใช้ .capture ทำให้เหตุการณ์ถูกจับจากองค์ประกอบแม่(parent) ลงมายัง
องค์ประกอบเป้าหมาย
<script setup> import { ref } from 'vue' function handleParentClick() { alert('Parent element clicked (capture phase)') } function handleButtonClick() { alert('Button clicked (bubbling phase)') } </script> <template> <div @click.capture="handleParentClick"> Parent Element <button @click="handleButtonClick">Click me</button> </div> </template>
รูปแบบนี้จะเป็นการกำหนดให้ เราสามารถตรวจจับ event ที่เกิดภายใน div ได้ ซึ่งปกติ ถ้า
เราไม่กำหนดค่าใดๆ event จะเกิดที่ปุ่ม แล้ว ก็มาเกิดที่ div แต่เมื่อเรากำหนดที่ตัว parent
หรือที่ตัว div ให้ทำการ capture event เมื่อเราคลิปที่ปุ่ม การทำงานจะเริ่มที่ div ก่อน
แล้วค่อยกลับไปทำงานที่ event ของปุ่ม นั่นคือ ทำฟังก์ชั่น handleParentClick แล้วตาม
ด้วยฟังก์ชั่น handleButtonClick
เราสามารถใช้ร่วมกับ ตัวปรับแต่งอื่นได้ เช่น ใช้กับ .stop เมื่อต้องการให้ทำงานเฉพาะที่ฟังก์ชั่น
handleParentClick ก็กำหนดค่าเป็น ดังนี้
<div @click.capture.stop="handleParentClick"> Parent Element <button @click="handleButtonClick">Click me</button> </div>
จากโค้ด ถึงเราจะกดที่ปุ่ม แต่ ฟังก์ชั่น handleButtonClick จะไม่ทำงาน จะทำงานที่ฟังก์ชั่น
handleParentClick แล้วไม่แพร่ event ลงมาที่ปุ่ม เพราะใช้ .stop
ตัวอย่างพื้นฐานของการใช้ .self
การใช้ .self modifier ใน Vue.js ช่วยให้เราสามารถจัดการเหตุการณ์เฉพาะเมื่อเหตุการณ์นั้น
ถูกเรียกใช้โดยตัวมันเอง ไม่ใช่โดยองค์ประกอบลูกหรือ descendant ภายในองค์ประกอบนั้น
วิธีนี้มีประโยชน์ในการป้องกันการจัดการเหตุการณ์ที่ไม่จำเป็นจากองค์ประกอบลูก
<script setup> import { ref } from 'vue' function handleDivClick() { alert('Div clicked') } function handleButtonClick() { alert('Button clicked') } </script> <template> <div @click.self="handleDivClick"> Parent Element <button @click="handleButtonClick">Click me</button> </div> </template>
เป็นการกำหนดให้ตัว DOM น้้นจะไม่รับ event ที่แพร่มา นั่นคือจะทำเฉพาะฟังก์ชั่นที่กำหนด
ถ้าเราคลิกที่ปุ่ม ถ้าไม่กำหนด .self ตัว div ก็จะได้รับ event จากการแพร่ไปด้วย แต่เมื่อเรา
กำหนด .self เป็นการระบุว่าจะใช้เฉพาะฟังก์ชั่นที่กำหนดเองเท่านั้น
ตัวอย่างพื้นฐานของการใช้ .once
การใช้ .once modifier ใน Vue.js ช่วยให้เราสามารถจัดการเหตุการณ์เพียงครั้งเดียว หลังจาก
ที่เหตุการณ์ถูกจัดการแล้ว, event listener จะถูกลบออก ซึ่งมีประโยชน์ในกรณีที่เราต้องการให้
บางการกระทำเกิดขึ้นเพียงครั้งเดียว เช่น การแสดงข้อความยืนยัน, การโหลดข้อมูลครั้งแรก,
หรือการเริ่มต้นบางอย่าง
<script setup> import { ref } from 'vue' const name = ref('') function handleClick() { alert('Button clicked') } function handleSubmit(event) { event.preventDefault(); // เพื่อป้องกันการส่งฟอร์มแบบปกติ alert('Form submitted with name: ' + name.value) // คุณสามารถเพิ่มการจัดการเพิ่มเติมที่นี่ เช่น การส่งข้อมูลไปยังเซิร์ฟเวอร์ } </script> <template> <form @submit.once="handleSubmit"> <input type="text" v-model="name" placeholder="Enter your name"> <button type="submit">Submit</button> </form> <button @click.once="handleClick">Click me once</button> </template>
เมื่อเรากำหนดใช้ตัวปรับแต่ง .once ฟังก์ชั่น handleSubmit กับ handleClick จะทำงานแค่
ครั้งแรกที่กดเท่านั้น เช่น ถ้าเรากดที่ปุ่ม คำสั่ง handleClick จะทำแค่ครั้งแรก ถ้ากดซ้ำก็ไม่ทำงาน
เช่นเดียวกันกับกรณีเรากดส่งข้อมูลฟอร์มเมื่อ submit จะทำคำสั่ง handleSubmit แค่ครั้งเดียว
ถ้าเรากดซ้ำ จะกลายเป็นส่งข้อมูลฟอร์มปกติ ไม่เข้าไปทำงานในฟังก์ชั่น handleSubmit อีก
จนกว่าจะโหลดหน้านั้นใหม่อีกครั้ง
ตัวอย่างพื้นฐานของการใช้ .passive
การใช้ .passive modifier ใน Vue.js เป็นวิธีที่ช่วยเพิ่มประสิทธิภาพของการจัดการเหตุการณ์
โดยเฉพาะอย่างยิ่งสำหรับเหตุการณ์ที่เกิดขึ้นบ่อยครั้ง เช่น scroll หรือ touchmove เมื่อใช้
.passive modifier, จะบอกเบราว์เซอร์ว่า event listener จะไม่เรียก event.preventDefault()
ซึ่งช่วยให้เบราว์เซอร์สามารถเพิ่มประสิทธิภาพการเลื่อน (scroll) หรือการแตะ (touch) ได้ดีขึ้น
ตัวปรับแต่ง .passive และ .prevent จะไม่ใช้งานร่วมกัน เพราะด้วยหลักการงานที่ขัดกัน
<script setup> import { ref } from 'vue' function handleScroll() { console.log('Scrolling...') } </script> <template> <div @scroll.passive="handleScroll" style="overflow-y: scroll; height: 200px;"> <div style="height: 1000px;"> Scroll me </div> </div> </template>
handleScroll method จะถูกเรียกทุกครั้งที่เราเลื่อน (scroll) ภายใน div
การใช้ .passive modifier จะช่วยให้การเลื่อนเกิดขึ้นได้อย่างราบรื่น โดยไม่ต้อง
รอการจัดการ preventDefault() เบราว์เซอร์รู้ว่า preventDefault() จะไม่ถูกเรียก
เพื่อไม่ให้เนื้อหาในตอนนี้ยาวเกินไป เราจะมาต่อในตอนหน้า ยังมีเกี่ยวกับการใช้งาน event
ต่างๆ ให้ศึกษาและทำความเข้าใจ รอติดตาม