การชี้ไปที่สิ่งต่างๆ ในเว็บเคยเป็นเรื่องง่าย คุณมีเมาส์ เลื่อนเมาส์ไปรอบๆ บางครั้งก็กดปุ่ม เท่านี้เอง ทุกอย่างที่ไม่ใช่เมาส์จะได้รับการจําลองให้เหมือนกับเมาส์ และนักพัฒนาแอปจะทราบได้อย่างชัดเจนว่าต้องคาดหวังอะไร
แต่ความเรียบง่ายไม่ได้หมายความว่าดีเสมอไป เมื่อเวลาผ่านไป การใช้อุปกรณ์ที่ไม่ใช่เมาส์ (หรืออุปกรณ์ที่เหมือนเมาส์) กลายเป็นสิ่งสําคัญมากขึ้น คุณสามารถใช้ปากกาที่ไวต่อแรงกดและรับรู้การเอียงเพื่อให้มีอิสระในการสร้างสรรค์อย่างน่าทึ่ง คุณสามารถใช้นิ้วได้ เพียงแค่มีอุปกรณ์และมือเท่านั้น และทำไมถึงไม่ใช้นิ้วมากกว่า 1 นิ้วด้วย
เรามีเหตุการณ์การแตะมาระยะหนึ่งแล้วเพื่อช่วยแก้ปัญหานี้ แต่เหตุการณ์ดังกล่าวเป็น API ที่แยกต่างหากทั้งหมดสําหรับการแตะโดยเฉพาะ ซึ่งทําให้คุณต้องเขียนโค้ดรูปแบบเหตุการณ์แยกกัน 2 รูปแบบหากต้องการรองรับทั้งเมาส์และการแตะ Chrome 55 มาพร้อมกับมาตรฐานใหม่ซึ่งรวมรูปแบบทั้ง 2 รูปแบบเข้าด้วยกัน ได้แก่ เหตุการณ์เคอร์เซอร์
รูปแบบเหตุการณ์เดียว
เหตุการณ์เคอร์เซอร์จะรวมรูปแบบอินพุตเคอร์เซอร์สำหรับเบราว์เซอร์เข้าด้วยกัน โดยรวมการสัมผัส ปากกา และเมาส์ไว้ในเหตุการณ์ชุดเดียว เช่น
document.addEventListener('pointermove',
ev => console.log('The pointer moved.'));
foo.addEventListener('pointerover',
ev => console.log('The pointer is now over foo.'));
ต่อไปนี้คือรายการเหตุการณ์ทั้งหมดที่ใช้ได้ ซึ่งน่าจะดูคุ้นเคยหากคุณคุ้นเคยกับเหตุการณ์เมาส์
pointerover
|
เคอร์เซอร์เข้าไปในกรอบพื้นที่ขององค์ประกอบ
การดำเนินการนี้จะเกิดขึ้นทันทีสำหรับอุปกรณ์ที่รองรับการโฮเวอร์ หรือก่อนเหตุการณ์ pointerdown สำหรับอุปกรณ์ที่ไม่รองรับ
|
pointerenter
|
คล้ายกับ pointerover แต่ไม่ทําให้ค่าบับเบิลและจัดการกับรายการสืบทอดในลักษณะที่ต่างกัน
รายละเอียดเกี่ยวกับข้อกำหนด
|
pointerdown
|
เคอร์เซอร์เข้าสู่สถานะปุ่มที่ใช้งานอยู่ โดยมีการปุ่มกดหรือมีการสร้างการเชื่อมต่อ ทั้งนี้ขึ้นอยู่กับความหมายของอุปกรณ์อินพุต |
pointermove
|
เคอร์เซอร์เปลี่ยนตำแหน่งแล้ว |
pointerup
|
เคอร์เซอร์ออกจากสถานะปุ่มที่ใช้งานอยู่ |
pointercancel
|
มีบางอย่างเกิดขึ้นซึ่งหมายความว่าเคอร์เซอร์จะไม่ส่งเหตุการณ์ใดๆ อีก ซึ่งหมายความว่าคุณควรยกเลิกการดำเนินการที่กำลังดำเนินอยู่และกลับไปที่สถานะอินพุตที่เป็นกลาง |
pointerout
|
เคอร์เซอร์ออกจากกล่องขอบเขตขององค์ประกอบหรือหน้าจอ และหลังจาก pointerup หากอุปกรณ์ไม่รองรับการโฮเวอร์
|
pointerleave
|
คล้ายกับ pointerout แต่ไม่ทําให้ค่าบับเบิลและจัดการกับรายการสืบทอดในลักษณะที่ต่างกัน
รายละเอียดเกี่ยวกับข้อกำหนด
|
gotpointercapture
|
องค์ประกอบได้รับการจับเคอร์เซอร์ |
lostpointercapture
|
ปล่อยเคอร์เซอร์ที่กำลังจับภาพ |
อินพุตประเภทต่างๆ
โดยทั่วไปแล้ว เหตุการณ์เคอร์เซอร์ช่วยให้คุณเขียนโค้ดในลักษณะที่ไม่ขึ้นอยู่กับอินพุตได้โดยไม่ต้องลงทะเบียนตัวแฮนเดิลเหตุการณ์แยกต่างหากสำหรับอุปกรณ์อินพุตแต่ละประเภท
แน่นอนว่าคุณยังคงต้องคำนึงถึงความแตกต่างระหว่างอินพุตประเภทต่างๆ เช่น แนวคิดของการวางเมาส์เหนือจะมีผลหรือไม่ หากต้องการแยกประเภทอุปกรณ์อินพุตที่แตกต่างกัน เช่น เพื่อระบุโค้ด/ฟังก์ชันแยกต่างหากสำหรับอินพุตที่แตกต่างกัน คุณก็ทำได้จากภายในตัวแฮนเดิลเหตุการณ์เดียวกันโดยใช้พร็อพเพอร์ตี้ pointerType
ของอินเทอร์เฟซ PointerEvent
ตัวอย่างเช่น หากคุณเขียนโค้ดลิ้นชักการนำทางด้านข้าง คุณอาจมีตรรกะต่อไปนี้ในเหตุการณ์ pointermove
switch(ev.pointerType) {
case 'mouse':
// Do nothing.
break;
case 'touch':
// Allow drag gesture.
break;
case 'pen':
// Also allow drag gesture.
break;
default:
// Getting an empty string means the browser doesn't know
// what device type it is. Let's assume mouse and do nothing.
break;
}
การดำเนินการเริ่มต้น
ในเบราว์เซอร์ที่เปิดใช้การสัมผัส จะใช้ท่าทางสัมผัสบางอย่างเพื่อเลื่อน ซูม หรือรีเฟรชหน้าเว็บ
ในกรณีของเหตุการณ์การสัมผัส คุณจะยังคงได้รับเหตุการณ์ขณะที่การดำเนินการเริ่มต้นเหล่านี้เกิดขึ้น เช่น touchmove
จะยังคงเริ่มทํางานขณะที่ผู้ใช้เลื่อนอยู่
เมื่อใช้เหตุการณ์เคอร์เซอร์ เมื่อใดก็ตามที่ทริกเกอร์การดำเนินการเริ่มต้น เช่น เลื่อนหรือซูม คุณจะได้รับเหตุการณ์ pointercancel
เพื่อแจ้งให้ทราบว่าเบราว์เซอร์ได้ควบคุมเคอร์เซอร์แล้ว เช่น
document.addEventListener('pointercancel',
ev => console.log('Go home, the browser is in charge now.'));
ความเร็วในตัว: รูปแบบนี้ช่วยให้ประสิทธิภาพดีขึ้นโดยค่าเริ่มต้นเมื่อเทียบกับเหตุการณ์การแตะ ซึ่งคุณต้องใช้โปรแกรมฟังเหตุการณ์แบบพาสซีฟเพื่อให้ได้การตอบสนองในระดับเดียวกัน
คุณหยุดไม่ให้เบราว์เซอร์ควบคุมได้ด้วยพร็อพเพอร์ตี้ CSS ของ touch-action
การตั้งค่าเป็น none
ในองค์ประกอบจะปิดใช้การดำเนินการทั้งหมดที่เบราว์เซอร์กำหนดไว้ซึ่งเริ่มต้นในองค์ประกอบนั้น แต่มีอีกหลายค่าสําหรับการควบคุมที่ละเอียดยิ่งขึ้น เช่น pan-x
สําหรับอนุญาตให้เบราว์เซอร์ตอบสนองต่อการเคลื่อนไหวในแนวแกน x แต่ไม่ใช่แนวแกน y Chrome 55รองรับค่าต่อไปนี้
auto
|
ค่าเริ่มต้น เบราว์เซอร์จะดําเนินการเริ่มต้นได้ |
none
|
เบราว์เซอร์ไม่ได้รับอนุญาตให้ดําเนินการเริ่มต้นใดๆ |
pan-x
|
เบราว์เซอร์ได้รับอนุญาตให้ดำเนินการตามค่าเริ่มต้นของการเลื่อนในแนวนอนเท่านั้น |
pan-y
|
เบราว์เซอร์ได้รับอนุญาตให้ดำเนินการเริ่มต้นด้วยการเลื่อนในแนวตั้งเท่านั้น |
pan-left
|
เบราว์เซอร์ได้รับอนุญาตให้ดำเนินการเริ่มต้นในการเลื่อนในแนวนอนเท่านั้น และเพื่อเลื่อนหน้าไปทางซ้ายเท่านั้น |
pan-right
|
เบราว์เซอร์ได้รับอนุญาตให้ดำเนินการเริ่มต้นในการเลื่อนในแนวนอนเท่านั้น และเพื่อเลื่อนหน้าเว็บไปทางขวาเท่านั้น |
pan-up
|
เบราว์เซอร์ได้รับอนุญาตให้ดำเนินการตามค่าเริ่มต้นของการเลื่อนแนวตั้งเท่านั้น และเพื่อเลื่อนหน้าขึ้นเท่านั้น |
pan-down
|
เบราว์เซอร์ได้รับอนุญาตให้ดำเนินการตามค่าเริ่มต้นของการเลื่อนแนวตั้งเท่านั้น และเพื่อเลื่อนหน้าลงเท่านั้น |
manipulation
|
เบราว์เซอร์ได้รับอนุญาตให้ดำเนินการเลื่อนและซูมเท่านั้น |
การจับภาพเคอร์เซอร์
เคยใช้เวลาหลายชั่วโมงในการแก้ไขข้อบกพร่องของmouseup
กิจกรรมที่ใช้งานไม่ได้ จนกว่าจะพบว่าเป็นเพราะผู้ใช้ปล่อยปุ่มนอกเป้าหมายการคลิกใช่ไหม หากไม่ โอเค อาจเป็นแค่เรา
แต่จนถึงตอนนี้ก็ยังไม่มีวิธีแก้ปัญหานี้ที่ดีจริงๆ ได้ คุณตั้งค่าตัวแฮนเดิล mouseup
ในเอกสารและบันทึกสถานะบางอย่างในแอปพลิเคชันเพื่อติดตามข้อมูลต่างๆ ได้ แต่วิธีนี้ไม่ใช่วิธีแก้ปัญหาที่เรียบร้อยที่สุด โดยเฉพาะในกรณีที่คุณสร้างคอมโพเนนต์เว็บและพยายามแยกทุกอย่างให้เรียบร้อย
เหตุการณ์เคอร์เซอร์เป็นโซลูชันที่ดีกว่ามาก เนื่องจากคุณสามารถจับภาพเคอร์เซอร์ได้เพื่อให้มั่นใจว่าคุณจะได้รับเหตุการณ์ pointerup
(หรือเหตุการณ์อื่นๆ ที่หลบเลี่ยงอยู่)
const foo = document.querySelector('#foo');
foo.addEventListener('pointerdown', ev => {
console.log('Button down, capturing!');
// Every pointer has an ID, which you can read from the event.
foo.setPointerCapture(ev.pointerId);
});
foo.addEventListener('pointerup',
ev => console.log('Button up. Every time!'));
การสนับสนุนเบราว์เซอร์
ขณะเขียนบทความนี้ เหตุการณ์เคอร์เซอร์ได้รับการรองรับใน Internet Explorer 11, Microsoft Edge, Chrome และ Opera รวมถึงได้รับการรองรับบางส่วนใน Firefox ดูรายการล่าสุดได้ที่ caniuse.com
คุณสามารถใช้ Pointer Events polyfill เพื่อเติมเต็มช่องว่างได้ หรือจะตรวจสอบการรองรับเบราว์เซอร์ที่รันไทม์ก็ทำได้ง่ายๆ ดังนี้
if (window.PointerEvent) {
// Yay, we can use pointer events!
} else {
// Back to mouse and touch events, I guess.
}
เหตุการณ์เคอร์เซอร์เป็นตัวเลือกที่ยอดเยี่ยมสำหรับการเพิ่มประสิทธิภาพแบบเป็นขั้นเป็นตอน เพียงแก้ไขเมธอดการเริ่มต้นเพื่อทำการทดสอบข้างต้น เพิ่มตัวแฮนเดิลเหตุการณ์เคอร์เซอร์ในบล็อก if
และย้ายตัวแฮนเดิลเหตุการณ์เมาส์/การสัมผัสไปยังบล็อก else
โปรดลองใช้แล้วบอกเราว่าคุณคิดเห็นอย่างไร