- ปุ่ม More บนเว็บไซต์ BBC UK ประมวลผลการคลิกล้มเหลวเฉพาะในสภาพแวดล้อมทำงานที่บ้านบางแบบ ทำให้บั๊ก UI ที่ดูธรรมดาแท้จริงแล้วเป็นปัญหาของระบบพิกัดแบบหลายจอภาพ
- เมื่อจอภาพภายนอกวางอยู่ ด้านบน·ด้านซ้าย ของจอภาพหลัก ค่า
screenX, screenY ในอีเวนต์ click ของ Chrome และ Firefox อาจกลายเป็นค่าติดลบได้
- โค้ดเดิมแยกแยะการคลิกด้วย pointer ด้วยเงื่อนไข
event.screenX > 0 || event.screenY > 0 จึงไม่มองว่า การคลิกที่มีพิกัดติดลบ เป็นการคลิกด้วยเมาส์
- การแก้ไขทำได้ง่าย ๆ โดยไม่ตรวจว่า
screenX, screenY มากกว่า 0 หรือไม่ แต่ตรวจว่า ไม่เท่ากับ 0 แทน กลายเป็นรูปแบบ event.type === 'click' && (event.screenX!== 0 || event.screenY!== 0)
- แม้จะผ่าน unit test, Puppeteer, การทดสอบด้วยมือ และการทดสอบด้วยเทคโนโลยีช่วยเหลือแล้ว บั๊กแบบนี้ก็ยังเหลืออยู่ได้เพราะความกำกวมของสเปก UI Events และ สมมติฐานเรื่องพิกัดหลายจอภาพ
บั๊กแถบนำทางของ BBC ที่เกิดซ้ำได้เฉพาะบางสภาพแวดล้อม
- แถบนำทางบนเว็บไซต์ BBC UK ทำหน้าที่เปิดเมนูเมื่อผู้ใช้เปิดใช้งาน ปุ่ม More
- ปุ่มนี้ใช้เหตุการณ์
click ซึ่งสามารถเกิดได้ไม่ใช่แค่จากเมาส์ แต่รวมถึง touch และปุ่ม Enter, Space บนคีย์บอร์ดด้วย
- สมาชิกทีมคนหนึ่งเจอปัญหาเฉพาะตอนใช้แล็ปท็อปทำงานที่บ้าน แต่ถ้าใช้แล็ปท็อปเครื่องเดียวกันที่ออฟฟิศกลับทำงานปกติ
- แม้อยู่ที่บ้าน ปัญหาก็เกิดเฉพาะเมื่อหน้าต่างเบราว์เซอร์อยู่บนจอภาพภายนอก ส่วนบนหน้าจอแล็ปท็อปปุ่มทำงานปกติ
- เมื่อเกิดปัญหา JavaScript handler จะไม่เปิดเมนู แต่เมนูจะเปิดด้วยพฤติกรรม no-JavaScript fallback แทน
- Safari ไม่พบปัญหาเดียวกันนี้
เงื่อนไขการเกิดซ้ำคือ ตำแหน่งของจอภาพ
- ทีมค่อย ๆ จำกัดเงื่อนไขการเกิดซ้ำ โดยตรวจดูว่าองค์ประกอบใดในสภาพแวดล้อมที่บ้านเป็นตัวกระตุ้นปัญหา
- จอภาพภายนอกถูกจัดวางไว้ ด้านบน ของหน้าจอแล็ปท็อป และเมื่อเปลี่ยนการจัดวางนี้ในการตั้งค่า OS ปัญหาก็หยุดเกิด
- สมาชิกทีมคนอื่นก็สามารถทำให้บั๊กเกิดซ้ำได้ เมื่อปรับการจัดวางจอภาพใน OS ให้ตรงกันด้วยวิธีเดียวกัน
- เงื่อนไขที่ตรวจพบในช่วงต้นมีสองข้อ
- ปัญหาไม่เกิดใน Safari
- ปัญหาเกิดเมื่อจอภาพภายนอกอยู่ ด้านบนและด้านซ้าย ของจอภาพหลัก
พิกัดติดลบของ screenX, screenY
- เมื่อตรวจเหตุการณ์
click ของปุ่ม More ด้วย console.log พบว่าใน Chrome และ Firefox ค่า screenX, screenY ออกมาเป็น ค่าติดลบ
- ไม่ว่าจะถูกกระตุ้นจากอินพุตแบบใด เหตุการณ์
click ก็เป็น PointerEvent ชนิดหนึ่ง ดังนั้น event object จึงมีข้อมูลของเมาส์หรือ touch pointer ที่ทำให้เกิดการคลิกอยู่ด้วย
screenX, screenY แสดงพิกัดของจุดที่ถูกคลิกบนหน้าจอเป็นหน่วยพิกเซล
- ใน DOM UI Events spec ไม่เห็นข้อมูลที่ระบุชัดเจนว่า property ดังกล่าวสามารถเป็นค่าติดลบได้หรือไม่
- ความแตกต่างระหว่าง Safari กับ Chrome·Firefox แสดงให้เห็นว่าในคอนฟิกแบบหลายจอภาพ เบราว์เซอร์แต่ละตัวอาจมี วิธีแสดงพิกัดหน้าจอ ต่างกัน
- ปัญหา interoperability นี้ถูกรายงานไปยังทีม WebKit แล้ว
ความแตกต่างของวิธีคิดพิกัดหลายจอภาพในแต่ละเบราว์เซอร์
- ในคอนฟิกแบบหลายจอภาพ ระบบพิกัดหน้าจอของเบราว์เซอร์ถือว่าจอหลายจอเป็นเหมือนหน้าจอขนาดใหญ่จอเดียว
- ถ้ามีจอภาพ 800px จำนวน 2 จอวางแนวนอน ช่วงพิกัด x อาจเป็นตั้งแต่ 0 ถึง 1600
- ใน Safari ช่วงพิกัดดูเหมือนจะเป็น ช่วงค่าบวก ที่เริ่มจากจอภาพซ้ายบนสุดเสมอ
- ใน Chrome และ Firefox พิกัดดูเหมือนจะคำนวณโดยอิงจากจอภาพหลัก ดังนั้นหน้าจอที่อยู่ด้านบนหรือด้านซ้ายของจอภาพหลักอาจให้พิกัดติดลบได้
- บั๊กครั้งนี้เกิดเฉพาะตอนที่
screenX, screenY เป็นค่าติดลบเท่านั้น
โค้ดที่มีปัญหาจริงและการแก้ไข
isInvokedByMouse ในโค้ดที่มีปัญหาพยายามตรวจว่าเหตุการณ์ click เกิดจากเมาส์หรือ touch pointer หรือไม่ โดยตรวจว่า screenX, screenY เป็นค่าบวกหรือไม่
const isInvokedByMouse = event => event.screenX > 0 || event.screenY > 0;
const isInvokedByKeyboard = event => isEnterKey(event) || isSpaceKey(event);
// ...
const toggleMenu = event => {
// ...
if (isInvokedByMouse(event) || isInvokedByKeyboard(event)) {
event.preventDefault();
// Do stuff to open the menu and move the focus...
}
};
- โค้ดนี้สมมติว่า
screenX, screenY ของเหตุการณ์ click ที่เกิดจาก pointer จะเป็น ค่าบวก
- เมื่อผู้ใช้คลิกปุ่ม
More บนจอภาพที่มีพิกัดหน้าจอติดลบ event handler จึงไม่ยอมรับว่าเป็นการคลิก และตกไปใช้พฤติกรรมปกติของลิงก์ More
- การแก้ไขคือแทนที่จะดูว่า
screenX, screenY มากกว่า 0 หรือไม่ ให้ตรวจว่า ไม่เท่ากับ 0 แทน
const isInvokedByMouse = event =>
event.type === 'click' && (event.screenX !== 0 || event.screenY !== 0);
- การเปลี่ยนแปลงนี้ทำให้ผู้ใช้ที่มีการจัดวางหลายจอภาพแบบเฉพาะตัวสามารถใช้แถบนำทางของเว็บไซต์ BBC ได้
ปัญหาการออกแบบที่ยังเหลือและการรีแฟกเตอร์ต่อมา
- แม้ตัวแก้ไขจะเรียบง่าย แต่ในโค้ดยังมีส่วนที่แปลกอยู่
- ไม่มีความจำเป็นต้องตรวจว่า
click เกิดจากเมาส์หรือคีย์บอร์ด และ event handler ก็ซับซ้อนขึ้นเพราะจัดการเหตุการณ์ keydown ด้วย
- ต้องระวังว่าวางสมมติฐานอะไรไว้กับพฤติกรรมของ API และการที่สเปกไม่ชัดเจนว่า
screenX, screenY สามารถเป็นค่าติดลบได้หรือไม่ ก็ช่วยซ่อนปัญหานี้ไว้
- โค้ดนี้ผ่าน unit test, การทดสอบด้วย Puppeteer, การทดสอบด้วยมือบนหลายเบราว์เซอร์·อุปกรณ์·เครื่องมือเทคโนโลยีช่วยเหลือแล้ว แต่ก็ยังไม่พบบั๊ก
- ตามการแก้ไขวันที่ 19 พฤศจิกายน 2024 คอมโพเนนต์นำทางถูกรีแฟกเตอร์ในภายหลัง และ event handler ของปุ่ม
menu ก็เปลี่ยนไปอย่างมาก
- บทความต่อเนื่องตอบเรื่องวิธีรีแฟกเตอร์และคำถามที่พบบ่อย: How I refactored the BBC navigation bar and a follow-up FAQ
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ขอเสริมสำหรับคนที่ยังไม่ได้กดเข้าไปดูรายงานบั๊กของ WebKit: นักพัฒนา WebKit ถาม BBC ว่าทำไมการตรวจจับว่าเป็นอีเวนต์ที่มาจากคีย์บอร์ดจึงมีประโยชน์ และผู้เขียนตอบว่าจำเป็นต้องมีความสามารถทำงานข้ามเบราว์เซอร์ได้เหมือนกันเพราะเป็น กรณีใช้งานด้านการเข้าถึง
ปุ่มเมนูบนแถบนำทางของเว็บไซต์ BBC ในสหราชอาณาจักรมีพฤติกรรมต่างกันเล็กน้อยระหว่างตอนเปิดด้วยพอยน์เตอร์กับตอนเปิดด้วยคีย์บอร์ด อีเวนต์คลิกจะเปิดเมนูเสมอ แต่ถ้าเปิดด้วยพอยน์เตอร์ โฟกัสจะย้ายไปที่คอนเทนเนอร์ของเมนู ส่วนถ้าเปิดด้วยคีย์บอร์ด โฟกัสจะย้ายไปที่ลิงก์แรกในเมนูโดยไม่มีแอนิเมชันเปิดเมนู อีเวนต์
clickเป็นอีเวนต์ที่ไม่ผูกกับอุปกรณ์ใดอุปกรณ์หนึ่ง จึงเหมาะสำหรับสร้างประสบการณ์ผู้ใช้บนคีย์บอร์ด และบนคีย์บอร์ดจะถูกเรียกด้วย Space หรือ Enter เท่านั้น ถ้าใช้keydownก็ต้องตรวจเองว่าเป็น Space/Enter หรือไม่ที่มา: https://bugs.webkit.org/show_bug.cgi?id=281430
const isInvokedByMouse = event => event.screenX > 0 || event.screenY > 0;และconst isInvokedByKeyboard = event => isEnterKey(event) || isSpaceKey(event);ซึ่งดูเผิน ๆ เหมือนพยายามจัดประเภทอีเวนต์ว่าเป็นเมาส์หรือคีย์บอร์ดอย่างใดอย่างหนึ่งแต่ในความเป็นจริงกลับเกิด 4 หมวดคือ เป็นเมาส์แต่ไม่ใช่คีย์บอร์ด, เป็นคีย์บอร์ดแต่ไม่ใช่เมาส์, เป็นทั้งคู่, และ ไม่ใช่ทั้งคู่ กรณี “ไม่ใช่ทั้งคู่” ถูกจัดการไม่เหมาะสมเหมือนบั๊กเดิม และยังสงสัยด้วยว่า “เป็นทั้งคู่” ทำงานถูกต้องหรือไม่ โค้ดควรจัดการอย่างตั้งใจว่าความเป็นคีย์บอร์ดกับความเป็นเมาส์เป็น boolean แยกกัน หรือไม่ก็ออกแบบให้
eventSourceคืนค่าเป็น หมวดที่ไม่ทับซ้อนกัน เช่น"keyboard","mouse","not sure"การออกแบบคอมโพเนนต์ให้สอดคล้องกับพฤติกรรมพื้นฐานและใช้ได้กับทั้งสองกรณีน่าจะดีกว่า ในเรื่องการเข้าถึง ไม่ควรพยายามทำตัวฉลาดเกินไป สุดท้ายมันกลายเป็นวิธีแก้ที่เกือบจะเป็นการแฮ็ก และแนวทางแบบนั้นย่อมพังหรือก่อผลข้างเคียงได้อยู่แล้ว เหตุผลที่ในบริบทการเข้าถึงแทบไม่มี handle ดี ๆ ให้แยกจัดการต่างกัน ก็เพราะตั้งแต่แรกมันไม่ใช่พื้นที่ที่ตั้งใจให้จัดการต่างกัน
ขณะเดียวกันก็ต้องการความสะดวกในการ bind กับอีเวนต์เดียว
clickทำให้ทำแบบนี้ได้ แต่ไม่มีทางรู้ว่าอีเวนต์เกิดจากการคลิกเมาส์หรือจากอินพุตคีย์บอร์ด จึงใช้ heuristic ที่ไม่เสถียร ใน Chrome ว่าถ้าตำแหน่งเมาส์เป็นscreenX=0,screenY=0ก็ถือว่าเป็นการคลิกที่จุดกำเนิดหรือถูก trigger จากคีย์บอร์ด จากประสบการณ์ที่เคยทำโปรเจกต์ด้านการเข้าถึง นี่เป็นไอเดียที่ค่อนข้างแย่ และถ้าเห็นใน PR ก็คงให้เขียนใหม่ แม้ในอุดมคติแล้วเบราว์เซอร์ควรมีพฤติกรรมเหมือนกัน แต่ปัญหาจริงดูเหมือนว่าในclickที่เกิดจากคีย์บอร์ดนั้นscreenXและscreenYแทบไม่มีความหมายตามอุดมคติ ไม่ควรปล่อย
MouseEventออกมา แต่ควรมีอีเวนต์ที่ทั่วไปกว่าและใช้ได้ทั้งคีย์บอร์ดกับเมาส์ เช่น"trigger"พร้อมให้ข้อมูลแหล่งที่มาของการ trigger เนื่องจากตอนนี้ยังไม่มีในสเปก และถ้าต้องการทางออกทันที การ bind กับkeydownด้วย แล้วถือว่าเป็นอินพุตคีย์บอร์ดเมื่อเกิดclickพร้อมกับkeydownบน element เดียวกัน น่าจะเสถียรกว่าและเป็นการแฮ็กน้อยกว่ามากscreenXและscreenYแต่ก็ยังสงสัยว่าทำไมscreenXต้องคืนค่าเป็น พิกัดหน้าจอจริง แทนที่จะเป็นตำแหน่งภายใน renderer หรือตำแหน่งในหน้าที่ render แล้วอย่างlayerX,layerYความต้องการของผู้เขียนสามารถตอบโจทย์ได้ด้วยตำแหน่งใน renderer และไม่จำเป็นต้องรั่วไหลตำแหน่งหน้าต่างเบราว์เซอร์ให้ทุกเว็บไซต์ที่เข้าไปเยี่ยมชม
don’tน่าจะเป็นคำผิดที่ทำให้ความหมายตรงข้ามกับเจตนาหรือเปล่าจากส่วนที่บอกว่า “แค่ต้องเปลี่ยน
isInvokedByMouseจากการตรวจว่าscreenXและscreenYมากกว่า 0 เป็นตรวจว่าไม่เท่ากับ 0 ก็พอแล้ว” แม้จะเกิดได้น้อยมาก แต่ก็สงสัยว่าถ้าผู้ใช้ คลิกเมาส์ที่ตำแหน่ง 0,0 จริง ๆ จะเป็นอย่างไรผมไม่คุ้นกับ JS นัก การตรวจ
!= 0นี่เป็นวิธีที่ดีที่สุดหรือเป็นวิธีเดียวจริงหรือ? พอกลับไปอ่านอีกครั้ง ดูเหมือนประโยคที่บอกว่า event handler จัดการkeydownด้วยเลยซับซ้อน และต้อง refactor เพิ่มภายหลัง แต่ตอนนี้การแก้นี้เพียงพอแล้ว น่าจะครอบคลุมประเด็นนี้อยู่บ้างinstanceof MouseEventแต่แบบนั้นก็ดูเสี่ยงหรือเหมือนการแฮ็กเช่นกันสงสัยว่าทำไมถึงต้องพึ่ง heuristic แบบนี้ อาจเป็นเพราะ
toggleMenuถูกใช้จาก event handler หลายตัว หรืออาจมีเหตุผลเฉพาะของ codebase อื่น ๆ ก็ได้ ถ้าไม่เห็นภาพรวมก็ตัดสินยาก คำตอบดูเหมือนอยู่ตรงนี้: https://news.ycombinator.com/item?id=42174177event.name == 'click'อยู่แล้ว ถ้าอย่างนั้นก็ไม่เข้าใจว่าทำไมต้องพยายามกรอง อีเวนต์คลิก ที่ปกติดีบางส่วนออกเมื่อก่อนเคยใช้เลือกว่าจะแสดงเลย์เอาต์แบบไหน ถ้าอยากฟังเฉพาะอินพุตแบบสัมผัส ก็ทำแบบนั้นแล้วเรียก
preventDefaultในอีเวนต์ เพื่อไม่ให้เบราว์เซอร์สร้างอีเวนต์clickต่อจากนั้น หรือไม่ก็ประหยัดแรงแล้วเขียน click handler ไปเลยเป็นเรื่องน่าชื่นชมที่ BBC ลงทุนด้านการเข้าถึง แล้วไปเจอบั๊กชวนหงุดหงิดแบบนี้ แต่ทำไมวงการนี้ถึงยังทำดรอปดาวน์ที่เปิดได้อย่างสม่ำเสมอสำหรับผู้ใช้ทุกคนให้ดีไม่ได้สักที?
การเข้าถึงมันยากขนาดนั้นเลยหรือ? BBC ควรใช้เว็บเฟรมเวิร์กหรือเว็บคอมโพเนนต์ที่จัดการเรื่องแบบนี้ไว้แล้วหรือเปล่า? ในฐานะนักพัฒนา full-stack ที่เน้นแบ็กเอนด์ ผมค่อนข้างระวังเวลาแตะคอมโพเนนต์ในเบราว์เซอร์ พฤติกรรมมีรายละเอียดปลีกย่อยเยอะ และ implementation ก็ผ่านการพิสูจน์มาเป็นเวลานานแล้ว เช่น การทำกล่องข้อความแบบ custom โดยไม่ศึกษาพฤติกรรมของกล่องข้อความในแต่ละแพลตฟอร์มอย่างลึกซึ้ง ดูเป็นอะไรที่ล้มเหลวได้ง่าย ผมเห็นบ่อยแม้แต่ในเว็บของบริษัทใหญ่ ๆ ว่าการคัดลอก/วางพัง หรือมีตัวอักษรหายไป ไม่เข้าใจว่าทำไมในปี 2024 กล่องข้อความถึงยังพังได้ และตอนนี้ React เริ่มให้ความรู้สึกหยิ่งผยองแล้ว
โดยส่วนตัวแล้วผมคงพยายามจัดการด้วยเทมเพลตฝั่งเซิร์ฟเวอร์, CSS framework อย่าง Bulma และ JS ให้น้อยที่สุด วิธีนี้อาจไม่เหมาะกับไซต์ที่ต้องการ branding แบบ custom เนียน ๆ แต่กล่องข้อความจะทำงานได้ดี และต้นทุนการพัฒนาก็ไม่เกินไป ผมไม่มั่นใจว่าจะผ่านมาตรฐานการเข้าถึงระดับ BBC หรือไม่
ตัวอย่างจริงคือ modal ถ้าคุณไม่ได้มีความบกพร่องทางการมองเห็น คุณจะเห็นกล่องสีขาวที่มี UI component ลอยอยู่บนพื้นที่สีเทาที่สื่อว่า “ห้ามแตะ” แต่ถ้าใช้ screen reader ก็ไม่มีอะไรรับประกันว่าจะได้รับข้อมูลนั้น เวลาใช้แท็บเลื่อนผ่านองค์ประกอบ UI แล้วกลับมาถึงด้านบนของกล่อง screen reader ตัวใดตัวหนึ่งจะบอกไหม? มันจะไล่รายการองค์ประกอบที่โต้ตอบได้หรือไม่? จะไล่ในลำดับเดียวกับ screen reader อื่นไหม? บนมือถือเป็นอย่างไร บน Mac ล่ะ? screen reader กับเบราว์เซอร์จะรายงาน input element อย่างถูกต้องไหม หรือจะปล่อยให้ผู้ใช้หลุดออกนอก modal กลับไปยังส่วนที่เหลือของไซต์อย่างเงียบ ๆ?
ในเรื่อง accessibility เราเชื่อไม่ได้ว่า OS, เบราว์เซอร์ และ screen reader จะทำงานร่วมกัน หรือทำงานอย่างสมเหตุสมผลในสถานการณ์ที่เหมาะสม เมื่อปี 2019 ผมต้องรายงานบั๊กใน VoiceOver + Safari ที่ negative CSS margin ทำให้ screen reader อ่านบล็อกข้อความ RTL สลับลำดับกัน มองด้วยตาเห็นเป็น
9/10/2019แต่ใน screen reader ได้ยินเหมือน “ten slash nine slash two-thousand-and-nineteen” และต้องแก้เฉพาะหน้าด้วยการใส่aria-hiddenให้ข้อความ แล้วเพิ่มแท็กpที่มองไม่เห็นซึ่งมีลำดับถูกต้องเข้าไป ดังนั้นเวลาเห็นโค้ดแปลก ๆ เกี่ยวกับ accessibility บางครั้งมันก็ไม่มีวิธีที่ดีกว่านั้นจริง ๆ ต่อให้พลิก codebase ทั้งหมดและให้ accessibility เป็นเรื่องสำคัญที่สุด ทันทีที่ JAWS หรือ VoiceOver อัปเดต ก็อาจพังแบบเข้าใจยากได้โดยรวมก็พอใช้ได้ แต่การที่ไฟล์
reset.cssมีอยู่ก็มีเหตุผลของมัน และในกรณีนี้ดูเหมือนว่าอาจใช้ แนวทางที่สุดโต่งกว่า เพื่อหลีกเลี่ยงปัญหาแบบนี้ทั้งหมด ผมกำลังพยายามอนุมานการตัดสินใจของพวกเขาอยู่นี่ดูเหมือนเป็นบั๊กที่สร้างขึ้นเองจาก heuristic ที่ผิด สมมติว่าถ้าค่า
screenX/Yเป็นบวกก็เป็น mouse event และการติดตาม/ล็อกข้อมูลไม่เพียงพอก็ทำให้การสืบสวนซับซ้อนขึ้นผมค่อนข้างแปลกใจที่แทนที่จะตรวจสอบ property ที่เหมาะสมกว่าอย่าง
pointerTypeตามที่คอมเมนต์อื่น ๆ เสนอ วิธีแก้ของผู้เขียนกลับเป็นการโปะ heuristic ที่โคลงเคลงเพิ่มเข้าไปอีก ประมาณว่าสรุปจากเบาะแสสองอย่างสุดท้ายว่า เวลาเช็กพิกัดscreenXและscreenYต้องเช็กค่าลบด้วย ไม่ใช่แค่ค่าบวกpointerId === -1แล้วค่อย fallback ไปที่screenX === 0เมื่อราว 4 ปีก่อนตอนที่โค้ดนี้ถูกเขียนขึ้น ไม่ใช่ทุกเบราว์เซอร์ที่ใช้ PointerEvent กับ
clickตั้งแต่แรกผมไม่เข้าใจว่าทำไมเว็บไซต์ถึงสามารถรู้ ตำแหน่งเมาส์ในระบบพิกัดของหน้าจอ ได้
window.screenX/window.screenYได้ และตำแหน่งคลิกก็อาจถูกรายงานในระบบพิกัดนั้นได้ ฟังดูไม่สมเหตุสมผลบนเดสก์ท็อปดูเหมือน TOR Browser จะปลอมค่า
screenXและscreenYเพื่อหลีกเลี่ยงการติดตามด้วย fingerprinting ผมสงสัยว่ามีใครเคยเห็น use case ที่ดีของฟีเจอร์นี้ไหม ที่นึกออกก็มีแอปพลิเคชันแบบสองหน้าต่างที่โต้ตอบกัน หรือไซต์ที่พฤติกรรมเปลี่ยนไปตามตำแหน่งบนหน้าจอเสมือนตัวอย่าง: https://youtu.be/3al8prbfK5o?si=loNtyqIfMFkppm5V
ผมไม่เข้าใจว่าทำไมไม่เช็ก
event.typeแต่ไปเช็กพิกัดแทน ถึงอย่างนั้นบทความเองก็เป็นปริศนาที่ดี และผมก็เข้าใจสถานการณ์ที่ต้องมองโค้ดที่ไม่ใช่ตัวเองเขียนแล้วถามว่า “ทำไมพิกัดคลิกต้องไม่เป็น 0 ถึงจะสำคัญ?”, “แค่เช็กว่าevent.targetเป็นปุ่มที่ต้องการ activate ไม่ได้หรือ?”, “ทำสิ่งเดียวกันด้วยแท็กdetails/summaryได้ แล้วทำไมต้องใช้ JavaScript?”ตั้งแต่แรกทำไมถึง filter ด้วย พิกัดหน้าจอ? ถ้าผู้ใช้ใช้อุปกรณ์ป้อนข้อมูลทางเลือกที่ไม่มีหน้าจอจะเป็นอย่างไร?
แค่
clickevent ก็น่าจะเป็นสัญญาณพอแล้วว่าผู้ใช้ตั้งใจเปิดเมนู ไม่เข้าใจว่าทำไมต้องประดิษฐ์ล้อขึ้นมาใหม่isInvokedByMouseตรวจว่าพิกัดscreenXหรือscreenYเป็นบวกหรือไม่ เพื่อดูว่าclickevent ถูกเรียกโดยเมาส์หรือ touch pointer ไม่ใช่คีย์บอร์ดกล่าวคือพยายามตรวจจับว่าเป็นการ activate ด้วยคีย์บอร์ดหรือด้วยเมาส์ และผู้เขียนก็สมมติว่าพิกัดหน้าจอของ mouse event จะเป็น ค่าบวก เสมอ
ผมได้เขียนบล็อกโพสต์เพิ่มอีกบทความเพื่ออธิบายบริบทที่ผู้คนสงสัยและตอบคำถามต่าง ๆ อธิบายว่าทำไมตอนแรกถึงตรวจสอบ
screenX === 0, ทำไมถึงต้องการพฤติกรรมที่ต่างกันตามการป้อนข้อมูลจากคีย์บอร์ดกับเมาส์ และรีแฟกเตอร์อย่างไรเพื่อป้องกันปัญหาเพิ่มเติมหวังว่าจะเป็นประโยชน์: https://www.joshtumath.uk/posts/2024-11-18-how-i-refactored-...
วิธีที่ถูกต้องในการตรวจสอบว่าเป็นการคลิกด้วยเมาส์หรือการคลิกด้วยคีย์บอร์ดคืออะไร? น่าจะอยากตั้งค่าแฟล็กระดับโมดูลตามอีเวนต์ที่เกิดขึ้นล่าสุด โดยถ้า
mousedownล่าสุดกว่าให้ตั้งisKeyboard=false,isMouse=trueและถ้าkeydownล่าสุดกว่าให้ตั้งกลับกันแบบนั้นก็ไม่ต้องมีฟังก์ชัน
isInvokedByMouseกับisInvokedByKeyboardแล้ว มีวิธีที่ดีกว่านี้ไหม? การ พึ่งพาพิกัดหน้าจอ สำหรับเรื่องนี้ดูน่าสงสัยมากและเหมือนเป็นการแฮ็กevent.detail[1] จะเป็น 0 สำหรับ “คลิก” จากคีย์บอร์ด และเป็น 1 สำหรับการคลิกด้วยพอยน์เตอร์1: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/det...
น่าสนใจมาก แต่ไม่เข้าใจว่าทำไมเบราว์เซอร์ถึงรายงานพิกัดต่างกันตามมอนิเตอร์ ผมเคยคิดว่าเบราว์เซอร์ปฏิบัติต่อเว็บเพจเหมือนอยู่เต็มหน้าจอไม่ว่าหน้านั้นจะอยู่บนจอแสดงผลไหนก็ตาม
มีเหตุผลอะไรที่ Web API ต้องมีข้อมูลแบบนี้ด้วยหรือ? ดูเหมือนเป็น ความเสี่ยงด้านความปลอดภัย·การรั่วไหลของข้อมูล·การติดตาม
นี่ไม่ใช่ปัญหาความสามารถของนักพัฒนาหรือ? ควรใช้ พิกัดของ viewport ไม่ใช่พิกัดหน้าจอ และควรอ่านค่าด้วย
.clientXกับ.clientYผมไม่เข้าใจว่าค่าติดลบในพื้นที่หน้าจอเป็นบั๊กตรงไหนhttps://developer.mozilla.org/en-US/docs/Web/CSS/CSSOM_view/...