ภาพรวมพื้นฐานเกี่ยวกับวิธีสร้างโมดัลมินิและเมกะที่ปรับสี ตอบสนอง และเข้าถึงได้โดยใช้องค์ประกอบ <dialog>
ในโพสต์นี้ เราต้องการแชร์แนวคิดเกี่ยวกับวิธีสร้างโมดัลขนาดเล็กและขนาดใหญ่ที่ปรับสีได้ ตอบสนอง และเข้าถึงได้โดยใช้องค์ประกอบ <dialog>
ลองใช้เดโมและดูซอร์สโค้ด
หากต้องการดูวิดีโอ โปรดดูโพสต์เวอร์ชัน YouTube ที่นี่
ภาพรวม
องค์ประกอบ <dialog>
เหมาะสําหรับข้อมูลหรือการดำเนินการตามบริบทในหน้า พิจารณาว่าประสบการณ์ของผู้ใช้จะได้รับประโยชน์จากการดำเนินการในหน้าเดียวกันแทนการดำเนินการในหลายหน้าหรือไม่ เช่น อาจเป็นเพราะแบบฟอร์มมีขนาดเล็ก หรือการดำเนินการเพียงอย่างเดียวที่ผู้ใช้ต้องทำคือยืนยันหรือยกเลิก
องค์ประกอบ <dialog>
ใช้งานได้อย่างเสถียรในเบราว์เซอร์ต่างๆ แล้ว
เราพบว่าองค์ประกอบขาดบางอย่าง ดังนั้นในภารกิจ GUI นี้ เราจึงเพิ่มรายการที่นักพัฒนาแอปควรได้รับ ซึ่งได้แก่ เหตุการณ์เพิ่มเติม การปิดแบบเบา การเคลื่อนไหวที่กําหนดเอง รวมถึงประเภทมินิและเมกะ
Markup
องค์ประกอบ <dialog>
ต้องมีข้อมูลที่จำเป็นเท่านั้น องค์ประกอบจะซ่อนโดยอัตโนมัติและมีสไตล์ในตัวเพื่อวางซ้อนเนื้อหา
<dialog>
…
</dialog>
เราปรับปรุงเกณฑ์พื้นฐานนี้ได้
โดยทั่วไปแล้ว องค์ประกอบกล่องโต้ตอบจะแชร์ข้อมูลจำนวนมากกับโมดัล และมักใช้ชื่อแทนกันได้ เราใช้องค์ประกอบกล่องโต้ตอบสำหรับทั้งป๊อปอัปกล่องโต้ตอบขนาดเล็ก (มินิ) และกล่องโต้ตอบแบบเต็มหน้า (เมกะ) เราตั้งชื่อว่า Mega และ Mini โดยปรับบทสนทนาทั้ง 2 แบบให้เหมาะกับกรณีการใช้งานที่แตกต่างกันเล็กน้อย
เราได้เพิ่มแอตทริบิวต์ modal-mode
ให้คุณระบุประเภท
<dialog id="MegaDialog" modal-mode="mega"></dialog>
<dialog id="MiniDialog" modal-mode="mini"></dialog>
ไม่ได้เสมอไป แต่โดยทั่วไประบบจะใช้องค์ประกอบกล่องโต้ตอบเพื่อรวบรวมข้อมูลการโต้ตอบบางอย่าง แบบฟอร์มภายในองค์ประกอบกล่องโต้ตอบสร้างขึ้นเพื่อใช้ร่วมกัน
คุณควรใช้องค์ประกอบแบบฟอร์มตัดเนื้อหากล่องโต้ตอบเพื่อให้ JavaScript เข้าถึงข้อมูลที่ผู้ใช้ป้อนได้ นอกจากนี้ ปุ่มภายในแบบฟอร์มที่ใช้ method="dialog"
สามารถปิดกล่องโต้ตอบได้โดยไม่ต้องใช้ JavaScript และส่งข้อมูล
<dialog id="MegaDialog" modal-mode="mega">
<form method="dialog">
…
<button value="cancel">Cancel</button>
<button value="confirm">Confirm</button>
</form>
</dialog>
กล่องโต้ตอบ Mega
กล่องโต้ตอบขนาดใหญ่มีองค์ประกอบ 3 รายการในแบบฟอร์ม ได้แก่
<header>
,
<article>
และ
<footer>
รายการเหล่านี้ทำหน้าที่เป็นคอนเทนเนอร์เชิงความหมาย รวมถึงเป้าหมายสไตล์สำหรับการแสดงกล่องโต้ตอบ ส่วนหัวจะตั้งชื่อโมดัลและมีปุ่มปิด บทความนี้มีไว้สำหรับข้อมูลและอินพุตในแบบฟอร์ม ส่วนท้ายมี<menu>
ปุ่มดำเนินการ
<dialog id="MegaDialog" modal-mode="mega">
<form method="dialog">
<header>
<h3>Dialog title</h3>
<button onclick="this.closest('dialog').close('close')"></button>
</header>
<article>...</article>
<footer>
<menu>
<button autofocus type="reset" onclick="this.closest('dialog').close('cancel')">Cancel</button>
<button type="submit" value="confirm">Confirm</button>
</menu>
</footer>
</form>
</dialog>
ปุ่มเมนูแรกมี autofocus
และ onclick
ตัวแฮนเดิลเหตุการณ์ในบรรทัด แอตทริบิวต์ autofocus
จะได้รับโฟกัสเมื่อเปิดกล่องโต้ตอบ และเราพบว่าแนวทางปฏิบัติแนะนำคือใส่แอตทริบิวต์นี้ในปุ่มยกเลิก ไม่ใช่ปุ่มยืนยัน วิธีนี้ช่วยให้มั่นใจได้ว่าการยืนยันเป็นการกระทำโดยเจตนาและไม่ได้เกิดขึ้นโดยไม่ตั้งใจ
กล่องโต้ตอบขนาดเล็ก
กล่องโต้ตอบขนาดเล็กคล้ายกับกล่องโต้ตอบขนาดใหญ่มาก เพียงแต่ไม่มีองค์ประกอบ <header>
วิธีนี้ช่วยให้ข้อความมีขนาดเล็กลงและสอดคล้องกับข้อความอื่นๆ มากขึ้น
<dialog id="MiniDialog" modal-mode="mini">
<form method="dialog">
<article>
<p>Are you sure you want to remove this user?</p>
</article>
<footer>
<menu>
<button autofocus type="reset" onclick="this.closest('dialog').close('cancel')">Cancel</button>
<button type="submit" value="confirm">Confirm</button>
</menu>
</footer>
</form>
</dialog>
องค์ประกอบกล่องโต้ตอบเป็นรากฐานที่แข็งแกร่งสําหรับองค์ประกอบวิวพอร์ตแบบเต็มที่สามารถรวบรวมข้อมูลและการโต้ตอบของผู้ใช้ ข้อมูลสําคัญเหล่านี้อาจทําให้การโต้ตอบในเว็บไซต์หรือแอปน่าสนใจและมีประสิทธิภาพ
การช่วยเหลือพิเศษ
องค์ประกอบกล่องโต้ตอบมีการช่วยเหลือพิเศษในตัวที่ดีมาก แทนที่จะเพิ่มฟีเจอร์เหล่านี้เหมือนที่มักจะทำ ฟีเจอร์หลายอย่างก็พร้อมใช้งานแล้ว
การคืนค่าโฟกัส
เช่นเดียวกับที่เราทำด้วยตนเองในการสร้างคอมโพเนนต์แถบด้านข้าง การเปิดและปิดอย่างถูกต้องจะต้องโฟกัสที่ปุ่มเปิดและปิดที่เกี่ยวข้อง เมื่อเมนูด้านข้างเปิดขึ้น โฟกัสจะอยู่ที่ปุ่มปิด เมื่อกดปุ่มปิด โฟกัสจะกลับไปยังปุ่มที่เปิด
ลักษณะการทำงานเริ่มต้นขององค์ประกอบกล่องโต้ตอบมีดังนี้
ขออภัย หากต้องการแสดงกล่องโต้ตอบแบบเคลื่อนไหว ฟังก์ชันนี้จะใช้งานไม่ได้ เราจะกู้คืนฟังก์ชันการทำงานนั้นในส่วน JavaScript
การโฟกัส
องค์ประกอบกล่องโต้ตอบจะจัดการ inert
ในเอกสารให้คุณ ก่อน inert
ระบบจะใช้ JavaScript เพื่อคอยดูว่าโฟกัสออกจากองค์ประกอบใด จากนั้นจะแทรกแซงและนำโฟกัสกลับเข้าไป
หลังจาก inert
คุณจะ "หยุด" ส่วนใดก็ได้ของเอกสารไว้ชั่วคราวเพื่อไม่ให้ส่วนนั้นๆ เป็นเป้าหมายโฟกัสหรือโต้ตอบกับเมาส์อีกต่อไป ระบบจะนําโฟกัสไปยังส่วนที่เป็นอินเทอร์แอกทีฟเพียงส่วนเดียวของเอกสารแทนที่จะตรึงโฟกัสไว้
เปิดและโฟกัสองค์ประกอบโดยอัตโนมัติ
โดยค่าเริ่มต้น องค์ประกอบกล่องโต้ตอบจะกำหนดโฟกัสให้กับองค์ประกอบที่โฟกัสได้รายการแรกในมาร์กอัปกล่องโต้ตอบ หากองค์ประกอบนี้ไม่ใช่องค์ประกอบที่ดีที่สุดสำหรับผู้ใช้ที่จะใช้เป็นค่าเริ่มต้น ให้ใช้แอตทริบิวต์ autofocus
ตามที่ได้อธิบายไปก่อนหน้านี้ เราพบว่าแนวทางปฏิบัติแนะนำคือการใส่ข้อความนี้บนปุ่มยกเลิก ไม่ใช่ปุ่มยืนยัน วิธีนี้ช่วยให้มั่นใจว่าผู้ใช้จะยืนยันโดยเจตนา ไม่ใช่ความผิดพลาด
การปิดด้วยแป้น Escape
สิ่งสำคัญคือต้องทำให้ผู้ใช้ปิดองค์ประกอบที่อาจรบกวนนี้ได้ง่ายๆ แต่โชคดีที่องค์ประกอบกล่องโต้ตอบจะจัดการแป้น Esc ให้คุณได้ คุณจึงไม่ต้องกังวลเรื่องการจัดเตรียม
รูปแบบ
การจัดสไตล์องค์ประกอบกล่องโต้ตอบนั้นทำได้ง่ายๆ และยาก วิธีที่ง่ายคือไม่เปลี่ยนพร็อพเพอร์ตี้การแสดงผลของกล่องโต้ตอบและทำงานภายใต้ข้อจำกัดของกล่องโต้ตอบ เราทํางานอย่างหนักเพื่อให้ภาพเคลื่อนไหวที่กําหนดเองสําหรับการเปิดและปิดกล่องโต้ตอบ การควบคุมพร็อพเพอร์ตี้ display
และอื่นๆ
การจัดแต่งโดยใช้พร็อพแบบเปิด
เราได้นำOpen Props ซึ่งเป็นไลบรารีตัวแปร CSS มาใช้อย่างเปิดเผยเพื่อเร่งการปรับสีและเพิ่มความสอดคล้องกันของการออกแบบโดยรวม นอกจากตัวแปรที่ระบุไว้ฟรีแล้ว เรายังนําเข้าไฟล์normalize และปุ่มบางรายการด้วย ซึ่ง Open Props มีให้นําเข้าหรือไม่ก็ได้ การนําเข้าเหล่านี้ช่วยให้ฉันมุ่งเน้นที่การปรับแต่งกล่องโต้ตอบและเดโมได้โดยไม่ต้องใช้สไตล์มากมายเพื่อรองรับและทำให้ดูดี
การจัดรูปแบบองค์ประกอบ <dialog>
การเป็นเจ้าของพร็อพเพอร์ตี้การแสดงผล
ลักษณะการทำงานเริ่มต้นของการแสดงและซ่อนองค์ประกอบกล่องโต้ตอบจะสลับคุณสมบัติการแสดงผลจาก block
เป็น none
ซึ่งหมายความว่าจะเคลื่อนไหวเข้าและออกไม่ได้ แต่จะเคลื่อนไหวเข้าได้เท่านั้น ฉันต้องการแสดงภาพเคลื่อนไหวทั้งแบบเข้าและออก โดยขั้นตอนแรกคือการตั้งค่าพร็อพเพอร์ตี้ display ของตัวเอง
dialog {
display: grid;
}
การเปลี่ยนแปลงค่าพร็อพเพอร์ตี้การแสดงผล ซึ่งหมายความว่าคุณเป็นเจ้าของค่าดังกล่าว ดังที่แสดงในตัวอย่างข้อมูล CSS ด้านบน จะทำให้ต้องจัดการสไตล์จำนวนมากเพื่อให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่เหมาะสม ประการแรก สถานะเริ่มต้นของกล่องโต้ตอบจะปิดอยู่ คุณสามารถแสดงสถานะนี้ด้วยภาพและป้องกันไม่ให้กล่องโต้ตอบได้รับการโต้ตอบด้วยสไตล์ต่อไปนี้
dialog:not([open]) {
pointer-events: none;
opacity: 0;
}
ตอนนี้กล่องโต้ตอบจะมองไม่เห็นและไม่สามารถโต้ตอบได้เมื่อไม่ได้เปิด เราจะเพิ่ม JavaScript บางส่วนในภายหลังเพื่อจัดการแอตทริบิวต์ inert
ในกล่องโต้ตอบ เพื่อให้ผู้ใช้แป้นพิมพ์และโปรแกรมอ่านหน้าจอเข้าถึงกล่องโต้ตอบที่ซ่อนอยู่ไม่ได้
กำหนดธีมสีแบบปรับเปลี่ยนได้ให้กับกล่องโต้ตอบ
แม้ว่า color-scheme
จะเลือกธีมสีแบบปรับเปลี่ยนได้ซึ่งเบราว์เซอร์มีให้สำหรับเอกสารของคุณเพื่อปรับตามค่ากำหนดของระบบเป็นธีมสว่างและธีมมืด แต่เราต้องการปรับแต่งองค์ประกอบกล่องโต้ตอบมากกว่านั้น Open Props มีสีพื้น 2-3 สีที่ปรับตามค่ากำหนดของระบบแบบสว่างและแบบมืดโดยอัตโนมัติ ซึ่งคล้ายกับการใช้ color-scheme
ฟีเจอร์เหล่านี้เหมาะอย่างยิ่งสำหรับการสร้างเลเยอร์ในการออกแบบ และเราชอบใช้สีเพื่อช่วยให้พื้นผิวของเลเยอร์ดูสมจริง สีพื้นหลังคือ var(--surface-1)
หากต้องการวางซ้อนบนเลเยอร์นั้น ให้ใช้ var(--surface-2)
dialog {
…
background: var(--surface-2);
color: var(--text-1);
}
@media (prefers-color-scheme: dark) {
dialog {
border-block-start: var(--border-size-1) solid var(--surface-3);
}
}
เราจะเพิ่มสีที่ปรับตามบริบทเพิ่มเติมในภายหลังสำหรับองค์ประกอบย่อย เช่น ส่วนหัวและส่วนท้าย เราถือว่าองค์ประกอบเหล่านี้เป็นองค์ประกอบเพิ่มเติมของกล่องโต้ตอบ แต่มีความสำคัญอย่างยิ่งในการสร้างการออกแบบกล่องโต้ตอบที่น่าสนใจและออกแบบมาอย่างดี
การปรับขนาดกล่องโต้ตอบตามอุปกรณ์
กล่องโต้ตอบจะกำหนดขนาดตามเนื้อหาโดยค่าเริ่มต้น ซึ่งโดยทั่วไปแล้วถือว่ายอดเยี่ยม เป้าหมายของเราคือการจำกัด max-inline-size
ให้มีขนาดที่อ่านได้ (--size-content-3
= 60ch
) หรือ 90% ของความกว้างของวิวพอร์ต วิธีนี้ช่วยให้กล่องโต้ตอบไม่กินพื้นที่เต็มหน้าจอในอุปกรณ์เคลื่อนที่ และจะไม่กว้างจนอ่านยากบนหน้าจอเดสก์ท็อป จากนั้นฉันจะเพิ่ม max-block-size
เพื่อให้กล่องโต้ตอบไม่สูงเกินความสูงของหน้า ซึ่งหมายความว่าเราจะต้องระบุตําแหน่งของพื้นที่ที่เลื่อนได้ของกล่องโต้ตอบด้วยในกรณีที่เป็นองค์ประกอบกล่องโต้ตอบที่สูง
dialog {
…
max-inline-size: min(90vw, var(--size-content-3));
max-block-size: min(80vh, 100%);
max-block-size: min(80dvb, 100%);
overflow: hidden;
}
สังเกตไหมว่าฉันมี max-block-size
2 ครั้ง รายการแรกใช้ 80vh
ซึ่งเป็นหน่วยวิวพอร์ตจริง สิ่งที่ฉันต้องการจริงๆ คือทำให้กล่องโต้ตอบอยู่ในลำดับที่สัมพันธ์กันสำหรับผู้ใช้ต่างชาติ ดังนั้นฉันจึงใช้หน่วย dvb
ที่เป็นตรรกะ ใหม่กว่า และรองรับเพียงบางส่วนในการประกาศครั้งที่ 2 เมื่อหน่วยดังกล่าวมีความเสถียรมากขึ้น
ตำแหน่งของกล่องโต้ตอบ Mega
หากต้องการช่วยจัดตําแหน่งองค์ประกอบกล่องโต้ตอบ คุณควรแยกออกเป็น 2 ส่วน ได้แก่ พื้นหลังแบบเต็มหน้าจอและคอนเทนเนอร์กล่องโต้ตอบ ฉากหลังต้องครอบคลุมทุกอย่าง โดยให้เอฟเฟกต์แสงเงาเพื่อแสดงให้เห็นว่ากล่องโต้ตอบนี้อยู่ด้านหน้าและเนื้อหาด้านหลังเข้าถึงไม่ได้ คอนเทนเนอร์กล่องโต้ตอบสามารถวางอยู่ตรงกลางพื้นหลังนี้และปรับรูปร่างตามเนื้อหาที่ต้องการ
สไตล์ต่อไปนี้จะยึดองค์ประกอบกล่องโต้ตอบกับหน้าต่าง ยืดให้คลุมมุมแต่ละมุม และใช้ margin: auto
เพื่อจัดเนื้อหาให้อยู่ตรงกลาง
dialog {
…
margin: auto;
padding: 0;
position: fixed;
inset: 0;
z-index: var(--layer-important);
}
รูปแบบกล่องโต้ตอบขนาดใหญ่บนอุปกรณ์เคลื่อนที่
ในวิวพอร์ตขนาดเล็ก ฉันจัดสไตล์ Mega Modal แบบเต็มหน้านี้ให้แตกต่างออกไปเล็กน้อย ฉันตั้งค่าระยะขอบด้านล่างเป็น 0
ซึ่งจะแสดงเนื้อหากล่องโต้ตอบที่ด้านล่างของวิวพอร์ต การปรับสไตล์เพียง 2-3 อย่างก็เปลี่ยนกล่องโต้ตอบเป็น ActionSheet ที่อยู่ใกล้กับนิ้วของผู้ใช้มากขึ้นได้
@media (max-width: 768px) {
dialog[modal-mode="mega"] {
margin-block-end: 0;
border-end-end-radius: 0;
border-end-start-radius: 0;
}
}
ตำแหน่งของกล่องโต้ตอบขนาดเล็ก
เมื่อใช้วิวพอร์ตขนาดใหญ่ เช่น ในคอมพิวเตอร์เดสก์ท็อป เราเลือกที่จะวางกล่องโต้ตอบขนาดเล็กเหนือองค์ประกอบที่เรียกให้แสดง เราต้องใช้ JavaScript จึงจะดำเนินการได้ ดูเทคนิคที่เราใช้ได้ที่นี่ แต่เราคิดว่าเทคนิคนี้อยู่นอกเหนือขอบเขตของบทความนี้ หากไม่มี JavaScript กล่องโต้ตอบขนาดเล็กจะปรากฏขึ้นตรงกลางหน้าจอ เช่นเดียวกับกล่องโต้ตอบขนาดใหญ่
องค์ประกอบต้องโดดเด่น
สุดท้าย ให้เพิ่มลูกเล่นให้กับกล่องโต้ตอบเพื่อให้ดูเหมือนพื้นผิวที่นุ่มนวลอยู่เหนือหน้าเว็บ ความนุ่มนวลนี้เกิดขึ้นจากการปัดมุมของกล่องโต้ตอบ คุณสามารถเพิ่มมิติความลึกได้ด้วยพร็อพเงาที่ Open Props ออกแบบมาอย่างพิถีพิถัน
dialog {
…
border-radius: var(--radius-3);
box-shadow: var(--shadow-6);
}
การปรับแต่งองค์ประกอบจำลองฉากหลัง
เราเลือกที่จะปรับพื้นหลังเพียงเล็กน้อย โดยเพิ่มเอฟเฟกต์เบลอด้วย backdrop-filter
ให้กับกล่องโต้ตอบขนาดใหญ่ ดังนี้
dialog[modal-mode="mega"]::backdrop {
backdrop-filter: blur(25px);
}
เรายังเลือกใส่ทรานซิชันใน backdrop-filter
ด้วย หวังว่าเบราว์เซอร์จะอนุญาตให้ใช้ทรานซิชันกับองค์ประกอบฉากหลังในอนาคต
dialog::backdrop {
transition: backdrop-filter .5s ease;
}
อุปกรณ์เสริมสำหรับจัดแต่ง
เราเรียกส่วนนี้ว่า "พิเศษ" เนื่องจากเกี่ยวข้องกับองค์ประกอบกล่องโต้ตอบในการแสดงตัวอย่างมากกว่าองค์ประกอบกล่องโต้ตอบโดยทั่วไป
การจำกัดการเลื่อน
เมื่อกล่องโต้ตอบแสดงขึ้น ผู้ใช้จะยังเลื่อนหน้าเว็บที่อยู่เบื้องหลังได้ ซึ่งเราไม่ต้องการ
โดยปกติแล้ว overscroll-behavior
จะเป็นวิธีแก้ปัญหาปกติ แต่ตามข้อกำหนด จะไม่มีผลกับกล่องโต้ตอบเนื่องจากไม่ใช่พอร์ตเลื่อน นั่นคือไม่ใช่ตัวเลื่อน จึงไม่มีอะไรที่จะป้องกัน ฉันสามารถใช้ JavaScript เพื่อรอเหตุการณ์ใหม่จากคู่มือนี้ เช่น "ปิด" และ "เปิด" และเปิด/ปิด overflow: hidden
ในเอกสาร หรือจะรอให้ :has()
ใช้งานได้อย่างเสถียรในเบราว์เซอร์ทุกรุ่นก็ได้
html:has(dialog[open][modal-mode="mega"]) {
overflow: hidden;
}
ตอนนี้เมื่อเปิดกล่องโต้ตอบขนาดใหญ่ เอกสาร html จะมี overflow: hidden
เลย์เอาต์ <form>
นอกเหนือจากที่จะเป็นองค์ประกอบที่สําคัญมากในการรวบรวมข้อมูลการโต้ตอบจากผู้ใช้แล้ว เรายังใช้องค์ประกอบนี้เพื่อวางเลย์เอาต์ส่วนหัว ส่วนท้าย และองค์ประกอบบทความ เลย์เอาต์นี้ตั้งใจจะแสดงองค์ประกอบย่อยของบทความเป็นพื้นที่ที่เลื่อนได้ เราทำสิ่งนี้ได้โดยใช้
grid-template-rows
องค์ประกอบบทความได้รับ 1fr
และแบบฟอร์มเองก็มีความสูงสูงสุดเท่ากับองค์ประกอบกล่องโต้ตอบ การตั้งค่าความสูงและขนาดแถวที่แน่นอนนี้เป็นสิ่งที่ทำให้องค์ประกอบบทความถูกจำกัดและเลื่อนเมื่อเนื้อหามีมากเกิน
dialog > form {
display: grid;
grid-template-rows: auto 1fr auto;
align-items: start;
max-block-size: 80vh;
max-block-size: 80dvb;
}
จัดรูปแบบกล่องโต้ตอบ <header>
บทบาทขององค์ประกอบนี้คือระบุชื่อสำหรับเนื้อหากล่องโต้ตอบและเสนอปุ่มปิดที่ค้นหาได้ง่าย รวมถึงมีการกำหนดสีพื้นผิวเพื่อให้ดูเหมือนอยู่หลังเนื้อหาของบทความในกล่องโต้ตอบ ข้อกำหนดเหล่านี้นำไปสู่คอนเทนเนอร์ Flexbox, รายการที่เรียงแนวตั้งโดยเว้นระยะห่างจากขอบ และระยะขอบและช่องว่างบางส่วนเพื่อให้มีที่ว่างสำหรับชื่อและปุ่มปิด
dialog > form > header {
display: flex;
gap: var(--size-3);
justify-content: space-between;
align-items: flex-start;
background: var(--surface-2);
padding-block: var(--size-3);
padding-inline: var(--size-5);
}
@media (prefers-color-scheme: dark) {
dialog > form > header {
background: var(--surface-1);
}
}
จัดรูปแบบปุ่มปิดส่วนหัว
เนื่องจากเดโมใช้ปุ่มเปิดพร็อพ จึงมีการปรับแต่งปุ่มปิดให้เป็นรูปปุ่มกลมที่มีไอคอนอยู่ตรงกลางดังต่อไปนี้
dialog > form > header > button {
border-radius: var(--radius-round);
padding: .75ch;
aspect-ratio: 1;
flex-shrink: 0;
place-items: center;
stroke: currentColor;
stroke-width: 3px;
}
จัดรูปแบบกล่องโต้ตอบ <article>
องค์ประกอบบทความมีบทบาทพิเศษในกล่องโต้ตอบนี้ เนื่องจากเป็นพื้นที่ที่มีไว้สำหรับการเลื่อนในกรณีที่กล่องโต้ตอบสูงหรือยาว
องค์ประกอบแบบฟอร์มหลักได้กำหนดค่าสูงสุดบางอย่างสำหรับตัวเองเพื่อจำกัดขนาดขององค์ประกอบบทความนี้ไม่ให้สูงเกินไป ตั้งค่า overflow-y: auto
เพื่อให้แถบเลื่อนแสดงขึ้นเมื่อจำเป็นเท่านั้น มีแถบเลื่อนภายในด้วย overscroll-behavior: contain
และส่วนที่เหลือจะเป็นสไตล์การนำเสนอที่กำหนดเอง
dialog > form > article {
overflow-y: auto;
max-block-size: 100%; /* safari */
overscroll-behavior-y: contain;
display: grid;
justify-items: flex-start;
gap: var(--size-3);
box-shadow: var(--shadow-2);
z-index: var(--layer-1);
padding-inline: var(--size-5);
padding-block: var(--size-3);
}
@media (prefers-color-scheme: light) {
dialog > form > article {
background: var(--surface-1);
}
}
จัดรูปแบบกล่องโต้ตอบ <footer>
บทบาทของส่วนท้ายคือมีเมนูปุ่มดำเนินการ ใช้ Flexbox เพื่อจัดแนวเนื้อหาให้อยู่ท้ายแกนบรรทัดของส่วนท้าย จากนั้นเว้นระยะห่างเล็กน้อยเพื่อให้ปุ่มมีพื้นที่พอ
dialog > form > footer {
background: var(--surface-2);
display: flex;
flex-wrap: wrap;
gap: var(--size-3);
justify-content: space-between;
align-items: flex-start;
padding-inline: var(--size-5);
padding-block: var(--size-3);
}
@media (prefers-color-scheme: dark) {
dialog > form > footer {
background: var(--surface-1);
}
}
จัดรูปแบบเมนูส่วนท้ายของกล่องโต้ตอบ
องค์ประกอบ menu
ใช้เพื่อบรรจุปุ่มดำเนินการสำหรับกล่องโต้ตอบ โดยใช้เลย์เอาต์ Flexbox แบบตัดขึ้นบรรทัดใหม่พร้อม gap
เพื่อให้มีช่องว่างระหว่างปุ่ม องค์ประกอบเมนูต้องมีระยะห่างจากขอบ เช่น <ul>
และนำรูปแบบนั้นออกด้วยเนื่องจากเราไม่ต้องการ
dialog > form > footer > menu {
display: flex;
flex-wrap: wrap;
gap: var(--size-3);
padding-inline-start: 0;
}
dialog > form > footer > menu:only-child {
margin-inline-start: auto;
}
แอนิเมชัน
องค์ประกอบของกล่องโต้ตอบมักมีภาพเคลื่อนไหวเนื่องจากจะเข้าสู่และออกจากหน้าต่าง การให้ภาพเคลื่อนไหวสนับสนุนสำหรับช่วงเข้าและออกของกล่องโต้ตอบนี้จะช่วยให้ผู้ใช้ปรับทิศทางตัวเองในขั้นตอนต่างๆ ได้
โดยปกติแล้ว องค์ประกอบกล่องโต้ตอบจะเคลื่อนไหวได้เฉพาะเมื่อปรากฏขึ้นเท่านั้น เนื่องจากเบราว์เซอร์จะเปิด/ปิดพร็อพเพอร์ตี้ display
ในองค์ประกอบ ก่อนหน้านี้ คำแนะนำจะตั้งค่าการแสดงผลเป็นตารางกริดและไม่เคยตั้งค่าเป็น "ไม่มี" ซึ่งจะปลดล็อกความสามารถในการทำให้ภาพเคลื่อนไหวเข้าและออก
Open Props มีคีย์เฟรมการเคลื่อนไหวมากมายให้ใช้งาน ซึ่งทำให้การจัดระเบียบง่ายและอ่านออกได้ เป้าหมายของภาพเคลื่อนไหวและแนวทางแบบเลเยอร์ที่เราใช้มีดังนี้
- การเคลื่อนไหวลดลงคือทรานซิชันเริ่มต้น ซึ่งเป็นการค่อยๆ ปรากฏและจางหายไปอย่างง่ายดาย
- หากการเคลื่อนไหวเรียบร้อยดี ระบบจะเพิ่มภาพเคลื่อนไหวแบบเลื่อนและปรับขนาด
- เลย์เอาต์อุปกรณ์เคลื่อนที่ที่ปรับเปลี่ยนตามพื้นที่โฆษณาสำหรับกล่องโต้ตอบขนาดใหญ่จะปรับให้เลื่อนออก
การเปลี่ยนค่าเริ่มต้นที่ปลอดภัยและมีความหมาย
แม้ว่าพร็อพแบบเปิดจะมีคีย์เฟรมสำหรับการค่อยๆ ปรากฏขึ้นและจางหายไป แต่ฉันชอบใช้ทรานซิชันแบบหลายเลเยอร์นี้เป็นค่าเริ่มต้น โดยมีภาพเคลื่อนไหวของคีย์เฟรมเป็นตัวเลือกการอัปเกรด ก่อนหน้านี้เราได้จัดสไตล์การแสดงผลของกล่องโต้ตอบด้วยค่าความทึบแสง โดยจัดเรียง 1
หรือ 0
ทั้งนี้ขึ้นอยู่กับแอตทริบิวต์ [open]
หากต้องการเปลี่ยนระหว่าง 0% ถึง 100% ให้บอกเบราว์เซอร์ว่าต้องการการเปลี่ยนแบบใดและระยะเวลาที่ต้องการ
dialog {
transition: opacity .5s var(--ease-3);
}
การเพิ่มการเคลื่อนไหวในทรานซิชัน
หากผู้ใช้ยอมรับการเคลื่อนไหว ทั้งกล่องโต้ตอบขนาดใหญ่และขนาดเล็กควรเลื่อนขึ้นเมื่อปรากฏขึ้น และเลื่อนออกเมื่อปิด คุณทําได้ด้วย prefers-reduced-motion
Media Query และ Open Prop 2-3 รายการ ดังนี้
@media (prefers-reduced-motion: no-preference) {
dialog {
animation: var(--animation-scale-down) forwards;
animation-timing-function: var(--ease-squish-3);
}
dialog[open] {
animation: var(--animation-slide-in-up) forwards;
}
}
การปรับภาพเคลื่อนไหวเมื่อออกสำหรับอุปกรณ์เคลื่อนที่
ก่อนหน้านี้ในส่วนการจัดสไตล์ เราได้ปรับสไตล์กล่องโต้ตอบขนาดใหญ่สำหรับอุปกรณ์เคลื่อนที่ให้คล้ายกับชีตการดำเนินการมากขึ้น ราวกับว่ากระดาษแผ่นเล็กเลื่อนขึ้นมาจากด้านล่างของหน้าจอและยังคงติดอยู่ที่ด้านล่าง ภาพเคลื่อนไหวการออกจากหน้าจอแบบปรับขนาดไม่เหมาะกับการออกแบบใหม่นี้มากนัก และเราสามารถปรับแต่งด้วย Media Query 2-3 รายการและ Open Prop บางรายการ ดังนี้
@media (prefers-reduced-motion: no-preference) and @media (max-width: 768px) {
dialog[modal-mode="mega"] {
animation: var(--animation-slide-out-down) forwards;
animation-timing-function: var(--ease-squish-2);
}
}
JavaScript
คุณเพิ่มสิ่งต่างๆ ต่อไปนี้ได้โดยใช้ JavaScript
// dialog.js
export default async function (dialog) {
// add light dismiss
// add closing and closed events
// add opening and opened events
// add removed event
// removing loading attribute
}
การเพิ่มเหล่านี้เกิดจากความต้องการในการปิดแบบเบาๆ (คลิกพื้นหลังของกล่องโต้ตอบ) ภาพเคลื่อนไหว และเหตุการณ์เพิ่มเติมบางอย่างเพื่อให้ได้เวลาในการรับข้อมูลแบบฟอร์มที่ดีขึ้น
การเพิ่มการปิดไฟ
งานนี้ทําได้ง่ายๆ และเป็นส่วนเสริมที่ยอดเยี่ยมสําหรับองค์ประกอบกล่องโต้ตอบที่ไม่ได้เคลื่อนไหว การโต้ตอบเกิดขึ้นจากการดูการคลิกองค์ประกอบกล่องโต้ตอบและใช้ประโยชน์จากการบับเบิลเหตุการณ์เพื่อประเมินสิ่งที่มีการคลิก และจะทำก็ต่อเมื่อเป็นองค์ประกอบบนสุดเท่านั้น ดังนี้
close()
export default async function (dialog) {
dialog.addEventListener('click', lightDismiss)
}
const lightDismiss = ({target:dialog}) => {
if (dialog.nodeName === 'DIALOG')
dialog.close('dismiss')
}
การแจ้งเตือน dialog.close('dismiss')
ระบบเรียกเหตุการณ์และระบุสตริง
JavaScript อื่นๆ สามารถดึงสตริงนี้เพื่อรับข้อมูลเชิงลึกเกี่ยวกับวิธีปิดกล่องโต้ตอบได้ คุณจะเห็นว่าเราระบุสตริงการปิดทุกครั้งที่เรียกใช้ฟังก์ชันจากปุ่มต่างๆ เพื่อให้บริบทแก่แอปพลิเคชันเกี่ยวกับการโต้ตอบของผู้ใช้
การเพิ่มเหตุการณ์ที่ปิดและปิดแล้ว
องค์ประกอบกล่องโต้ตอบมาพร้อมกับเหตุการณ์ปิด ซึ่งจะแสดงทันทีเมื่อมีเรียกใช้ฟังก์ชัน close()
dialog เนื่องจากเรากำลังสร้างภาพเคลื่อนไหวขององค์ประกอบนี้ จึงควรมีเหตุการณ์ก่อนและหลังภาพเคลื่อนไหวสำหรับการเปลี่ยนแปลงในการดึงข้อมูลหรือรีเซ็ตแบบฟอร์มกล่องโต้ตอบ เราใช้แอตทริบิวต์นี้เพื่อจัดการการเพิ่มแอตทริบิวต์ inert
ในกล่องโต้ตอบแบบปิด และในตัวอย่าง เราใช้แอตทริบิวต์เหล่านี้เพื่อแก้ไขรายการรูปโปรไฟล์หากผู้ใช้ส่งรูปภาพใหม่
ในการสร้างเหตุการณ์ใหม่ 2 รายการชื่อ closing
และ closed
จากนั้นฟังเหตุการณ์ปิดในตัวในกล่องโต้ตอบ จากที่นี่ ให้ตั้งค่ากล่องโต้ตอบเป็น inert
แล้วส่งเหตุการณ์ closing
งานถัดไปคือรอให้ภาพเคลื่อนไหวและทรานซิชันทำงานในกล่องโต้ตอบจนเสร็จ แล้วจึงส่งเหตุการณ์ closed
const dialogClosingEvent = new Event('closing')
const dialogClosedEvent = new Event('closed')
export default async function (dialog) {
…
dialog.addEventListener('close', dialogClose)
}
const dialogClose = async ({target:dialog}) => {
dialog.setAttribute('inert', '')
dialog.dispatchEvent(dialogClosingEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogClosedEvent)
}
const animationsComplete = element =>
Promise.allSettled(
element.getAnimations().map(animation =>
animation.finished))
ฟังก์ชัน animationsComplete
ซึ่งใช้ในการสร้างคอมโพเนนต์ Toast ด้วย จะแสดงผลตามพรอมต์ที่เสร็จสมบูรณ์ของภาพเคลื่อนไหวและพรอมต์การเปลี่ยน ด้วยเหตุนี้ dialogClose
จึงต้องเป็นฟังก์ชันแบบแอ็กซิงก์ จากนั้นจึงสามารถawait
ส่งคืนพรอมต์และดำเนินการต่อไปยังเหตุการณ์แบบปิดได้อย่างมั่นใจ
การเพิ่มกิจกรรมที่เปิดและกิจกรรมที่เปิด
เหตุการณ์เหล่านี้เพิ่มได้ยากกว่า เนื่องจากองค์ประกอบกล่องโต้ตอบในตัวไม่มีเหตุการณ์เปิดเหมือนที่มีสำหรับเหตุการณ์ปิด ฉันใช้ MutationObserver เพื่อแสดงข้อมูลเชิงลึกเกี่ยวกับการเปลี่ยนแปลงแอตทริบิวต์ของกล่องโต้ตอบ ในเครื่องมือตรวจสอบนี้ ฉันจะคอยดูการเปลี่ยนแปลงแอตทริบิวต์ "เปิด" และจัดการเหตุการณ์ที่กําหนดเองตามความเหมาะสม
สร้างเหตุการณ์ใหม่ 2 รายการโดยตั้งชื่อว่า opening
และ opened
เช่นเดียวกับที่เราเริ่มเหตุการณ์ที่ปิดและปิดแล้ว ก่อนหน้านี้เราคอยฟังเหตุการณ์การปิดกล่องโต้ตอบ แต่ครั้งนี้จะใช้ Mutation Observer ที่สร้างขึ้นเพื่อดูแอตทริบิวต์ของกล่องโต้ตอบ
…
const dialogOpeningEvent = new Event('opening')
const dialogOpenedEvent = new Event('opened')
export default async function (dialog) {
…
dialogAttrObserver.observe(dialog, {
attributes: true,
})
}
const dialogAttrObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(async mutation => {
if (mutation.attributeName === 'open') {
const dialog = mutation.target
const isOpen = dialog.hasAttribute('open')
if (!isOpen) return
dialog.removeAttribute('inert')
// set focus
const focusTarget = dialog.querySelector('[autofocus]')
focusTarget
? focusTarget.focus()
: dialog.querySelector('button').focus()
dialog.dispatchEvent(dialogOpeningEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogOpenedEvent)
}
})
})
ระบบจะเรียกใช้ฟังก์ชัน Callback ของ Mutation Observer เมื่อมีการทําการเปลี่ยนแปลงแอตทริบิวต์ของกล่องโต้ตอบ โดยระบุรายการการเปลี่ยนแปลงเป็นอาร์เรย์ วนซ้ำการเปลี่ยนแปลงแอตทริบิวต์เพื่อหา attributeName
ที่เปิดอยู่ ถัดไป ให้ตรวจสอบว่าองค์ประกอบมีแอตทริบิวต์หรือไม่ ซึ่งจะบอกได้ว่ากล่องโต้ตอบเปิดขึ้นหรือไม่ หากเปิดอยู่ ให้นําแอตทริบิวต์ inert
ออก ตั้งค่าโฟกัสไปที่องค์ประกอบที่ขอ autofocus
หรือองค์ประกอบ button
รายการแรกที่พบในกล่องโต้ตอบ สุดท้าย ให้ส่งเหตุการณ์เปิดทันที รอให้ภาพเคลื่อนไหวเสร็จสิ้น แล้วส่งเหตุการณ์ที่เปิด
การเพิ่มกิจกรรมที่นําออกแล้ว
ในแอปพลิเคชันหน้าเว็บเดียว มักจะมีการเพิ่มและนำกล่องโต้ตอบออกตามเส้นทางหรือความต้องการและสถานะอื่นๆ ของแอปพลิเคชัน ซึ่งอาจมีประโยชน์ในการล้างข้อมูลเหตุการณ์หรือข้อมูลเมื่อนำกล่องโต้ตอบออก
คุณทําได้ด้วยเครื่องมือตรวจสอบการเปลี่ยนแปลงรายการอื่น ในครั้งนี้ เราจะสังเกตองค์ประกอบย่อยขององค์ประกอบ body และคอยดูว่ามีการนําองค์ประกอบกล่องโต้ตอบออกหรือไม่ แทนที่จะสังเกตแอตทริบิวต์ในองค์ประกอบกล่องโต้ตอบ
…
const dialogRemovedEvent = new Event('removed')
export default async function (dialog) {
…
dialogDeleteObserver.observe(document.body, {
attributes: false,
subtree: false,
childList: true,
})
}
const dialogDeleteObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(mutation => {
mutation.removedNodes.forEach(removedNode => {
if (removedNode.nodeName === 'DIALOG') {
removedNode.removeEventListener('click', lightDismiss)
removedNode.removeEventListener('close', dialogClose)
removedNode.dispatchEvent(dialogRemovedEvent)
}
})
})
})
ระบบจะเรียกใช้การเรียกกลับของ Mutation Observer ทุกครั้งที่มีการเพิ่มหรือนำรายการย่อยออกจากเนื้อหาของเอกสาร การกลายพันธุ์ที่เฉพาะเจาะจงซึ่งระบบจะติดตามมีไว้สำหรับ removedNodes
ที่มี nodeName
ของกล่องโต้ตอบ หากนํากล่องโต้ตอบออก ระบบจะนำเหตุการณ์การคลิกและการปิดออกเพื่อเพิ่มพื้นที่ว่างในหน่วยความจํา และระบบจะส่งเหตุการณ์ที่นําออกเอง
การนำแอตทริบิวต์การโหลดออก
เราได้เพิ่มแอตทริบิวต์การโหลดลงในกล่องโต้ตอบเพื่อป้องกันไม่ให้ภาพเคลื่อนไหวของกล่องโต้ตอบเล่นภาพเคลื่อนไหวตอนออกเมื่อเพิ่มลงในหน้าเว็บหรือเมื่อโหลดหน้าเว็บ สคริปต์ต่อไปนี้จะรอให้ภาพเคลื่อนไหวของกล่องโต้ตอบทำงานเสร็จ แล้วจึงนำแอตทริบิวต์ออก ตอนนี้กล่องโต้ตอบจะแสดงผลแบบเคลื่อนไหวเข้าและออกได้อิสระ และเราซ่อนภาพเคลื่อนไหวที่ทำให้เสียสมาธิได้อย่างมีประสิทธิภาพ
export default async function (dialog) {
…
await animationsComplete(dialog)
dialog.removeAttribute('loading')
}
ดูข้อมูลเพิ่มเติมเกี่ยวกับปัญหาการป้องกันภาพเคลื่อนไหวคีย์เฟรมเมื่อโหลดหน้าเว็บ ที่นี่
รวมกันทั้งหมด
ต่อไปนี้คือ dialog.js
ฉบับเต็มหลังจากที่เราได้อธิบายแต่ละส่วนแยกกันไปแล้ว
// custom events to be added to <dialog>
const dialogClosingEvent = new Event('closing')
const dialogClosedEvent = new Event('closed')
const dialogOpeningEvent = new Event('opening')
const dialogOpenedEvent = new Event('opened')
const dialogRemovedEvent = new Event('removed')
// track opening
const dialogAttrObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(async mutation => {
if (mutation.attributeName === 'open') {
const dialog = mutation.target
const isOpen = dialog.hasAttribute('open')
if (!isOpen) return
dialog.removeAttribute('inert')
// set focus
const focusTarget = dialog.querySelector('[autofocus]')
focusTarget
? focusTarget.focus()
: dialog.querySelector('button').focus()
dialog.dispatchEvent(dialogOpeningEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogOpenedEvent)
}
})
})
// track deletion
const dialogDeleteObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(mutation => {
mutation.removedNodes.forEach(removedNode => {
if (removedNode.nodeName === 'DIALOG') {
removedNode.removeEventListener('click', lightDismiss)
removedNode.removeEventListener('close', dialogClose)
removedNode.dispatchEvent(dialogRemovedEvent)
}
})
})
})
// wait for all dialog animations to complete their promises
const animationsComplete = element =>
Promise.allSettled(
element.getAnimations().map(animation =>
animation.finished))
// click outside the dialog handler
const lightDismiss = ({target:dialog}) => {
if (dialog.nodeName === 'DIALOG')
dialog.close('dismiss')
}
const dialogClose = async ({target:dialog}) => {
dialog.setAttribute('inert', '')
dialog.dispatchEvent(dialogClosingEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogClosedEvent)
}
// page load dialogs setup
export default async function (dialog) {
dialog.addEventListener('click', lightDismiss)
dialog.addEventListener('close', dialogClose)
dialogAttrObserver.observe(dialog, {
attributes: true,
})
dialogDeleteObserver.observe(document.body, {
attributes: false,
subtree: false,
childList: true,
})
// remove loading attribute
// prevent page load @keyframes playing
await animationsComplete(dialog)
dialog.removeAttribute('loading')
}
การใช้ข้อบังคับ dialog.js
ฟังก์ชันที่ส่งออกจากโมดูลจะคาดหวังว่าจะมีการเรียกใช้และส่งผ่านองค์ประกอบกล่องโต้ตอบที่ต้องการเพิ่มเหตุการณ์และฟังก์ชันการทำงานใหม่เหล่านี้
import GuiDialog from './dialog.js'
const MegaDialog = document.querySelector('#MegaDialog')
const MiniDialog = document.querySelector('#MiniDialog')
GuiDialog(MegaDialog)
GuiDialog(MiniDialog)
เพียงเท่านี้ กล่องโต้ตอบ 2 รายการก็ได้รับการอัปเกรดด้วยการปิดเบาๆ การแก้ไขภาพเคลื่อนไหวขณะโหลด และเหตุการณ์อื่นๆ เพิ่มเติม
การฟังเหตุการณ์ที่กําหนดเองใหม่
ตอนนี้องค์ประกอบกล่องโต้ตอบที่อัปเกรดแล้วแต่ละรายการจะรับฟังเหตุการณ์ใหม่ได้ 5 รายการ ดังนี้
MegaDialog.addEventListener('closing', dialogClosing)
MegaDialog.addEventListener('closed', dialogClosed)
MegaDialog.addEventListener('opening', dialogOpening)
MegaDialog.addEventListener('opened', dialogOpened)
MegaDialog.addEventListener('removed', dialogRemoved)
ตัวอย่างการจัดการเหตุการณ์เหล่านั้นมีดังนี้
const dialogOpening = ({target:dialog}) => {
console.log('Dialog opening', dialog)
}
const dialogClosed = ({target:dialog}) => {
console.log('Dialog closed', dialog)
console.info('Dialog user action:', dialog.returnValue)
if (dialog.returnValue === 'confirm') {
// do stuff with the form values
const dialogFormData = new FormData(dialog.querySelector('form'))
console.info('Dialog form data', Object.fromEntries(dialogFormData.entries()))
// then reset the form
dialog.querySelector('form')?.reset()
}
}
ในตัวอย่างที่ฉันสร้างด้วยองค์ประกอบกล่องโต้ตอบ ฉันใช้เหตุการณ์ที่ปิดแล้วและข้อมูลแบบฟอร์มนั้นเพื่อเพิ่มองค์ประกอบรูปโปรไฟล์ใหม่ลงในรายการ จังหวะเวลาดีมากตรงที่กล่องโต้ตอบแสดงภาพเคลื่อนไหวตอนออกจนเสร็จ แล้วสคริปต์บางส่วนก็แสดงภาพเคลื่อนไหวในรูปโปรไฟล์ใหม่ เหตุการณ์ใหม่ช่วยให้การประสานประสบการณ์ของผู้ใช้เป็นไปอย่างราบรื่นยิ่งขึ้น
โปรดทราบว่า dialog.returnValue
: มีสตริงปิดที่ส่งเมื่อเรียกเหตุการณ์ dialog close()
ข้อมูลในเหตุการณ์ dialogClosed
มีความสำคัญอย่างยิ่งในการระบุว่ากล่องโต้ตอบถูกปิด ยกเลิก หรือยืนยัน หากยืนยันแล้ว สคริปต์จะดึงค่าของแบบฟอร์มและรีเซ็ตแบบฟอร์ม การรีเซ็ตมีประโยชน์เมื่อกล่องโต้ตอบแสดงขึ้นอีกครั้ง กล่องโต้ตอบจะว่างเปล่าและพร้อมสำหรับการส่งใหม่
บทสรุป
ตอนนี้คุณรู้วิธีที่เราทำแล้ว คุณจะทำอย่างไรบ้าง 🙂
มาลองใช้แนวทางที่หลากหลายและดูวิธีทั้งหมดในการสร้างบนเว็บกัน
สร้างเดโม แล้วทวีตลิงก์มาหาเรา เราจะเพิ่มลงในส่วนรีมิกซ์ของชุมชนด้านล่าง
รีมิกซ์ของชุมชน
- @GrimLink พร้อมกล่องโต้ตอบแบบ 3-in-1
- @mikemai2awesome กับรีมิกซ์ที่ยอดเยี่ยมซึ่งไม่เปลี่ยนพร็อพเพอร์ตี้
display
- @geoffrich_ กับ Svelte และ Svelte FLIP ที่ขัดเงาอย่างดี
แหล่งข้อมูล
- ซอร์สโค้ดใน GitHub
- รูปโปรไฟล์ Doodle