อินเทอร์เฟซแชทจำนวนมากจะส่งข้อความเมื่อผู้ใช้กด Enter ใน <textarea>
ซึ่งวิธีนี้ใช้ได้กับผู้ใช้ที่พิมพ์ด้วยการป้อนข้อมูลโดยตรงจากแป้นพิมพ์ภาษาละติน (เช่น ภาษาอังกฤษ) แต่จะใช้ไม่ได้กับผู้ใช้ที่พิมพ์ด้วยตัวแก้ไขวิธีการป้อนข้อมูล (IME) เพื่อเขียนข้อความในภาษาต่างๆ เช่น ญี่ปุ่น จีน หรือเกาหลี
ในบริบทเหล่านี้ แป้น Enter/Return จะใช้เพื่อยืนยันตัวเลือกการแปลงอักขระปัจจุบัน หาก JavaScript ที่กำหนดเองคอยฟัง keydown ใน Enter และส่งทันที ระบบจะส่งข้อความของผู้ใช้ขณะที่ยังแปลงอักขระอยู่ ซึ่งส่งผลให้ข้อความไม่สมบูรณ์ กระจัดกระจาย หรือไม่ถูกต้อง
การตรวจสอบการเปิดใช้งานการจัดองค์ประกอบจะมีผลกับแฮนเดิล keydown ที่กำหนดเองซึ่งดำเนินการกับ Enter ไม่ใช่เฉพาะช่อง <textarea> แบบหลายบรรทัด ช่อง <input> บรรทัดเดียวที่มีการจัดการ Enter ของตัวเอง เช่น แถบค้นหาและค้นพบ ช่องเปลี่ยนชื่อในบรรทัด ช่องกล่องโต้ตอบโมดัล และชุดคำสั่ง จะได้รับคีย์ดาวน์ Enter ที่ยืนยัน IME เหมือนกับที่ <textarea> ได้รับ โดยตั้งค่า isComposing เป็น true การส่ง <form> โดยนัยแบบเนทีฟจาก <input> ที่ไม่มีเครื่องมือจัดการ Enter ที่กำหนดเองไม่จำเป็นต้องมีการจัดการที่ชัดเจน เนื่องจากเบราว์เซอร์จะระงับการส่งโดยนัยเมื่อ IME ใช้การกดแป้นพิมพ์ Enter
กลยุทธ์การติดตั้งใช้งาน
สำหรับ <textarea> หรือ <input> ที่มีการกด Enter เพื่อส่งแบบกำหนดเอง ให้ตรวจสอบพร็อพเพอร์ตี้ isComposing แบบเนทีฟของ KeyboardEvent ก่อนส่งเนื้อหา นอกจากนี้ ให้เรียก event.preventDefault(): การดำเนินการเริ่มต้นของ Enter จะแทรกการขึ้นบรรทัดใหม่ใน <textarea> และใน <input> ภายใน <form> จะทริกเกอร์การส่งโดยนัยของเบราว์เซอร์ ซึ่งจะส่งเป็นครั้งที่ 2
<form id="chat-form">
<label for="chat-input" class="visually-hidden">Message</label>
<textarea id="chat-input" placeholder="Type a message..."></textarea>
<button type="submit" id="send-button">Send</button>
</form>
const textarea = document.getElementById('chat-input');
const form = document.getElementById('chat-form');
textarea.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && !event.shiftKey) {
// Prevent the default action (newline in a textarea, implicit form submission in an input)
event.preventDefault();
// If the user is composing text, return early.
if (event.isComposing) {
return;
}
form.requestSubmit();
}
});
สำหรับ <input> บรรทัดเดียว ให้ใช้ตัวแฮนเดิลเดียวกันโดยไม่มีเงื่อนไข !event.shiftKey ซึ่งมีอยู่เนื่องจาก Shift+Enter แทรกการขึ้นบรรทัดใหม่ใน <textarea> เท่านั้น
การช่วยเหลือพิเศษและการทดสอบ
- ปุ่มส่งที่ชัดเจน: ใส่เอลิเมนต์
<button type="submit">เสมอ แป้นพิมพ์ลัดเป็นตัวช่วย จึงต้องไม่แทนที่เส้นทางการส่งแบบฟอร์มในตัว - อินพุตที่เข้าถึงได้: ตรวจสอบว่าองค์ประกอบ
<input>และ<textarea>ทั้งหมดเชื่อมโยงกับ<label>โดยใช้แอตทริบิวต์idและforที่ตรงกัน
กลยุทธ์สำรอง
ใน Safari เวอร์ชันล่าสุด ปัญหาการจัดลำดับเหตุการณ์ (ข้อบกพร่อง WebKit 165004) ส่ง compositionend ไปยังเครื่องมือจัดการสคริปต์ก่อนที่จะยืนยัน Enter keydown แม้ว่าเหตุการณ์ที่เกี่ยวข้องจะถูกส่งไปในลำดับที่ตรงกันข้ามก็ตาม เมื่อตัวแฮนเดิล keydown ทำงาน event.isComposing ได้รับการรีเซ็ตเป็น false แล้ว ซึ่งหมายความว่าการตรวจสอบมาตรฐานเพียงอย่างเดียวจะไม่สามารถป้องกันการส่งก่อนเวลาอันควรได้
หากต้องการรองรับความเข้ากันได้ข้ามเบราว์เซอร์ใน Safari เวอร์ชันเก่าและแพลตฟอร์มอื่นๆ ให้ใช้กลยุทธ์สำรองอย่างใดอย่างหนึ่งต่อไปนี้
กลยุทธ์ที่ 1: เพิ่มการตรวจสอบ keyCode === 229 (แนะนำ)
การจับคู่ event.isComposing กับการตรวจสอบ event.keyCode === 229 จะช่วยให้คุณตรวจจับการยืนยันการกดปุ่ม Enter ที่ไม่เป็นไปตามลำดับของ Safari ได้อย่างน่าเชื่อถือ เนื่องจากโค้ดนี้ซ้อนอยู่ภายใต้เกต event.key === 'Enter' จึงปลอดภัยจากแป้นพิมพ์เสมือนบนอุปกรณ์เคลื่อนที่ที่อาจใช้ 229 สำหรับการป้อนเลย์เอาต์อักขระปกติ
textarea.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
// Block submission if composing natively or if keyCode is 229
if (event.isComposing || event.keyCode === 229) {
return;
}
form.requestSubmit();
}
});
กลยุทธ์ที่ 2: วิธีแก้ปัญหาเกี่ยวกับกรอบเวลา event.timeStamp (ทางเลือก)
สำหรับฐานของโค้ดที่ห้ามใช้ API ที่เลิกใช้งานแล้วอย่าง keyCode โดยเด็ดขาด หรือหากมีปัญหาที่ทราบเกี่ยวกับการตรวจสอบ 229 ในสภาพแวดล้อมเป้าหมายที่เฉพาะเจาะจง คุณสามารถติดตามการประทับเวลาการส่งเหตุการณ์ที่เบราว์เซอร์รายงานแทนได้
เนื่องจาก Safari ส่งเหตุการณ์ Enter keydown ที่ยืนยันใกล้กับเหตุการณ์ compositionend มาก (มักจะอยู่ภายใน 5 มิลลิวินาที และบางครั้งการประทับเวลา keydown จะเร็วกว่าเล็กน้อยเนื่องจากการกลับลำดับการนำส่งของแฮนเดิล) การตรวจสอบความแตกต่างของเวลาจึงมีความน่าเชื่อถือสูงและไม่น่าจะทริกเกอร์ผลบวกลวงบนแป้นพิมพ์เสมือนบนอุปกรณ์เคลื่อนที่ภายใต้สภาวะมาตรฐาน
let lastCompositionEndAt = null;
textarea.addEventListener('compositionend', (event) => {
// IMPORTANT: Always use event.timeStamp, not Date.now() or performance.now().
// Handler-time measurements are vulnerable to drift when the main thread is blocked.
lastCompositionEndAt = event.timeStamp;
});
textarea.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
if (event.isComposing) {
return;
}
// Block submission if the event occurs within a 50ms window of composition ending.
// Math.abs handles Safari's inverted event delivery timing bug.
if (
lastCompositionEndAt !== null &&
Math.abs(event.timeStamp - lastCompositionEndAt) < 50
) {
return;
}
form.requestSubmit();
}
});