ภาพรวมพื้นฐานของวิธีสร้างโมดัลขนาดเล็กและโมดัลขนาดใหญ่ที่ปรับเปลี่ยนได้ ปรับเปลี่ยนตามอุปกรณ์ และเข้าถึงง่ายด้วยเอลิเมนต์ <dialog>
ในโพสต์นี้ ผมอยากจะแชร์ความคิดเห็นเกี่ยวกับวิธีสร้างมินิโมดัลขนาดใหญ่และขนาดเล็กที่
สามารถปรับสีได้ และเข้าถึงได้ง่ายๆ ด้วยเอลิเมนต์ <dialog>
ลองใช้การสาธิตและดูแหล่งที่มา!
หากต้องการดูวิดีโอ โปรดใช้โพสต์นี้ในเวอร์ชัน YouTube
ภาพรวม
องค์ประกอบ <dialog>
เหมาะอย่างยิ่งสำหรับข้อมูลหรือการดำเนินการตามบริบทในหน้าเว็บ พิจารณาว่าเมื่อใดที่ประสบการณ์ของผู้ใช้จะได้ประโยชน์จากการดำเนินการของหน้าเว็บเดียวกันแทนการดำเนินการแบบหลายหน้า ซึ่งอาจเป็นเพราะฟอร์มมีขนาดเล็กหรือการดำเนินการเดียวที่จำเป็นจากผู้ใช้คือการยืนยันหรือยกเลิก
องค์ประกอบ <dialog>
มีความเสถียรในเบราว์เซอร์ต่างๆ เมื่อเร็วๆ นี้:
ฉันพบว่าองค์ประกอบหายไป 2-3 รายการ ดังนั้นในภารกิจ GUI นี้ ฉันจึงเพิ่มรายการประสบการณ์ของนักพัฒนาซอฟต์แวร์ที่คาดไว้ ได้แก่ กิจกรรมเพิ่มเติม การปิดไฟ ภาพเคลื่อนไหวที่กำหนดเอง รวมถึงประเภทมินิและขนาดใหญ่
Markup
องค์ประกอบที่สำคัญขององค์ประกอบ <dialog>
คือไม่ซับซ้อน องค์ประกอบดังกล่าวจะถูกซ่อนไว้โดยอัตโนมัติ และมีรูปแบบในตัวเพื่อวางซ้อนเนื้อหาของคุณ
<dialog>
…
</dialog>
เราสามารถปรับปรุงเกณฑ์พื้นฐานนี้ได้
แต่เดิมนั้น องค์ประกอบกล่องโต้ตอบมักจะใช้ร่วมกับโมดัลหลายโมดัลอยู่ และบ่อยครั้งที่ชื่อนั้นใช้แทนกันได้ ผมได้อิสระในการใช้องค์ประกอบกล่องโต้ตอบสำหรับทั้งป๊อปอัปกล่องโต้ตอบขนาดเล็ก (ขนาดเล็ก) และกล่องโต้ตอบแบบเต็มหน้า (ขนาดใหญ่) ผมตั้งชื่อว่า "เมกะและมินิ" โดยกล่องโต้ตอบทั้ง 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
คุณควรปิดองค์ประกอบที่อาจรบกวนนี้ได้ง่ายๆ โชคดีที่องค์ประกอบกล่องโต้ตอบจะจัดการคีย์ Escape ให้คุณ ช่วยให้คุณไม่ต้องเสียเวลาไปกับการจัดระเบียบเป็นกลุ่ม
รูปแบบ
มีเส้นทางที่ง่ายในการจัดรูปแบบองค์ประกอบกล่องโต้ตอบและเส้นทางที่ยาก เส้นทางที่ทำได้ง่ายดายนี้มาจากการไม่เปลี่ยนคุณสมบัติการแสดงผลของกล่องโต้ตอบและทำงานโดยมีข้อจำกัด ผมจะลงลึกไปตามเส้นทางที่ยากเพื่อสร้างภาพเคลื่อนไหวที่กำหนดเองสำหรับ
เปิดและปิดกล่องโต้ตอบ ควบคุมพร็อพเพอร์ตี้ display
และอีกมากมาย
การจัดรูปแบบด้วยอุปกรณ์ประกอบแบบเปิด
ฉันจึงนำ Open Props มาใส่ลงในไลบรารีตัวแปร CSS เพื่อเร่งให้สีที่ปรับได้และความสอดคล้องของการออกแบบโดยรวมเร็วขึ้น นอกเหนือจากตัวแปรที่มีให้ฟรีแล้ว เรายังนำเข้าไฟล์ทำให้เป็นมาตรฐานและปุ่มบางปุ่มอีกด้วย ซึ่ง Open Props จะเป็นตัวนำเข้าที่ไม่บังคับให้ทั้ง 2 ปุ่ม การนำเข้าเหล่านี้ช่วยให้ผมมุ่งเน้นไปที่การปรับแต่งกล่องโต้ตอบและการสาธิต ในขณะที่ไม่ต้องใช้รูปแบบมากมายเพื่อสนับสนุนและทำให้ดูดี
การจัดรูปแบบองค์ประกอบ <dialog>
การเป็นเจ้าของพร็อพเพอร์ตี้การแสดงผล
ลักษณะการทำงานเริ่มต้นในการแสดงหรือซ่อนองค์ประกอบกล่องโต้ตอบจะสลับพร็อพเพอร์ตี้การแสดงผลจาก block
เป็น none
ซึ่งหมายความว่าคุณไม่สามารถเคลื่อนไหวได้
ทั้งในและนอก มีเฉพาะใน ฉันอยากให้เคลื่อนไหวทั้งขาเข้าและขาออก และขั้นตอนแรกคือ
ตั้งค่าพร็อพเพอร์ตี้
display ของฉันเอง
dialog {
display: grid;
}
เมื่อเปลี่ยนแปลงและเป็นเจ้าของมูลค่าพร็อพเพอร์ตี้ Display ดังที่แสดงในข้อมูลโค้ด CSS ด้านบน จึงต้องจัดการรูปแบบจำนวนมากเพื่ออำนวยความสะดวกให้แก่ผู้ใช้ที่เหมาะสม อย่างแรก สถานะเริ่มต้นของกล่องโต้ตอบคือ ปิดไป คุณสามารถแสดงสถานะนี้เป็นภาพและป้องกันไม่ให้กล่องโต้ตอบรับการโต้ตอบกับรูปแบบต่อไปนี้
dialog:not([open]) {
pointer-events: none;
opacity: 0;
}
ตอนนี้กล่องโต้ตอบจะมองไม่เห็นและไม่สามารถโต้ตอบได้เมื่อไม่ได้เปิดอยู่ หลังจากนี้ ฉันจะเพิ่ม JavaScript บางอย่างเพื่อจัดการแอตทริบิวต์ inert
ในกล่องโต้ตอบเพื่อให้แน่ใจว่าผู้ใช้แป้นพิมพ์และโปรแกรมอ่านหน้าจอจะเข้าถึงกล่องโต้ตอบที่ซ่อนอยู่ไม่ได้
กำหนดธีมสีแบบปรับอัตโนมัติให้กล่องโต้ตอบ
แม้ว่า color-scheme
จะเลือกให้เอกสารของคุณใช้ธีมสีที่ปรับได้ซึ่งมาจากเบราว์เซอร์ตามค่ากำหนดของระบบสว่างและมืด แต่ฉันก็อยากปรับแต่งองค์ประกอบกล่องโต้ตอบมากกว่านั้น Open Props มีสีพื้นผิวบางส่วนที่จะปรับตามค่ากำหนดของระบบสว่างและมืดโดยอัตโนมัติ ซึ่งคล้ายกับการใช้ 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);
}
รูปแบบกล่องโต้ตอบขนาดใหญ่สำหรับอุปกรณ์เคลื่อนที่
ในวิวพอร์ตขนาดเล็ก ฉันจัดรูปแบบโมดัลขนาดใหญ่แบบเต็มหน้านี้แตกต่างกันเล็กน้อย ฉันตั้งค่าขอบด้านล่างเป็น 0
ซึ่งจะแสดงเนื้อหากล่องโต้ตอบที่ด้านล่างของวิวพอร์ต ผมเปลี่ยนกล่องโต้ตอบเป็น
แผ่นงานการดำเนินการที่ใกล้กับนิ้วหัวแม่มือของผู้ใช้มากขึ้นได้ 2 ครั้ง
@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);
}
}
การจัดรูปแบบปุ่มปิดส่วนหัว
เนื่องจากการสาธิตนั้นใช้ปุ่ม Open Props จึงมีการปรับแต่งปุ่มปิด ให้เป็นไอคอนทรงกลมที่มีปุ่มเป็นศูนย์กลาง เช่น
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 มาพร้อมภาพเคลื่อนไหวของคีย์เฟรมมากมายสำหรับการใช้งาน ซึ่งทำให้การจัดแนวเป็นกลุ่มง่ายและอ่านง่าย เป้าหมายภาพเคลื่อนไหวและวิธี แบบเลเยอร์ที่ผมทำมีดังนี้
- การเคลื่อนไหวที่ลดลงคือการเปลี่ยนผ่านที่เป็นค่าเริ่มต้น ซึ่งจะลดความทึบแสงเข้าและออกได้ง่าย
- หากการเคลื่อนไหวเหมาะสม ระบบจะเพิ่มภาพเคลื่อนไหวแบบเลื่อนและปรับขนาด
- มีการปรับเลย์เอาต์อุปกรณ์เคลื่อนที่ที่ปรับเปลี่ยนตามอุปกรณ์สำหรับกล่องโต้ตอบขนาดใหญ่ให้เลื่อนออก
การเปลี่ยนการใช้งานเริ่มต้นที่ปลอดภัยและมีความหมาย
แม้ว่า Open Props จะมีคีย์เฟรมสำหรับการเฟดเข้าและออก แต่ฉันชอบการเปลี่ยนแบบเลเยอร์นี้เป็นค่าเริ่มต้นโดยมีภาพเคลื่อนไหวของคีย์เฟรมเป็นการอัปเกรดที่เป็นไปได้ ก่อนหน้านี้ เราได้จัดรูปแบบการเปิดเผยของกล่องโต้ตอบให้เป็นแบบทึบแสงแล้ว โดยจัดกลุ่ม 1
หรือ 0
ตามแอตทริบิวต์ [open]
หากต้องการสลับระหว่าง 0% ถึง 100% ให้บอกเบราว์เซอร์ว่าต้องการระยะเวลาและการค่อยๆ เปลี่ยนประเภทใด ดังนี้
dialog {
transition: opacity .5s var(--ease-3);
}
การเพิ่มการเคลื่อนไหวให้กับการเปลี่ยน
หากผู้ใช้สามารถเคลื่อนไหวได้ กล่องโต้ตอบขนาดใหญ่และกล่องโต้ตอบขนาดเล็ก
ควรเลื่อนขึ้นเป็นทางเข้าและปรับขนาดเมื่อออก ซึ่งทำได้โดยใช้คิวรี่สื่อ prefers-reduced-motion
และ Open Props ต่อไปนี้
@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;
}
}
การปรับภาพเคลื่อนไหวเมื่อออกจากแอปสำหรับอุปกรณ์เคลื่อนที่
ก่อนหน้านี้ในส่วนการจัดรูปแบบ รูปแบบกล่องโต้ตอบขนาดใหญ่จะได้รับการปรับเปลี่ยนสำหรับอุปกรณ์เคลื่อนที่ให้มีลักษณะเหมือนแผ่นงาน ราวกับมีกระดาษเล็กๆ เลื่อนขึ้นจากด้านล่างของหน้าจอและยังคงแนบอยู่กับด้านล่าง ภาพเคลื่อนไหวที่ปรับขนาดออกไม่สอดคล้องกับการออกแบบใหม่นี้ และเราสามารถนำมาปรับใช้กับคำค้นหาสื่อ 2-3 รายการและ Open Props บางอย่างได้ ดังนี้
@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()
เนื่องจากเรากำลังทำให้องค์ประกอบนี้เคลื่อนไหว จึงเป็นเรื่องดีหากมีเหตุการณ์ทั้งก่อนและหลังภาพเคลื่อนไหว การเปลี่ยนแปลงเพื่อดึงข้อมูลหรือรีเซ็ตฟอร์มกล่องโต้ตอบ ฉันใช้ที่นี่เพื่อจัดการการเพิ่มแอตทริบิวต์ 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
ซึ่งใช้ในการสร้างคอมโพเนนต์ข้อความโทสต์ด้วยเช่นกัน จะแสดงคำสัญญาโดยอิงตามความสมบูรณ์ของภาพเคลื่อนไหวและการเปลี่ยนฉาก นี่เป็นเหตุผลที่ dialogClose
เป็นฟังก์ชันอะซิงโครนัส ซึ่งก็จะสามารถ
await
คำมั่นสัญญาที่ให้ไว้และเดินหน้าไปสู่กิจกรรมแบบปิดได้อย่างมั่นใจ
กำลังเพิ่มเหตุการณ์เปิดและกิจกรรมที่เปิดอยู่
การเพิ่มเหตุการณ์เหล่านี้ไม่ใช่เรื่องง่ายนักเนื่องจากองค์ประกอบกล่องโต้ตอบในตัวไม่ได้ให้เหตุการณ์ที่เปิดอยู่เหมือนปิด ฉันใช้ MutationObserver เพื่อให้ข้อมูลเชิงลึกเกี่ยวกับการเปลี่ยนแปลงแอตทริบิวต์ของกล่องโต้ตอบ ในโปรแกรมสังเกตการณ์นี้ ผมจะคอยดูการเปลี่ยนแปลงของแอตทริบิวต์แบบเปิดและจัดการเหตุการณ์ ที่กำหนดเองตามความเหมาะสม
สร้างเหตุการณ์ใหม่ 2 รายการชื่อว่า opening
และ opened
ซึ่งคล้ายกับการเริ่มเหตุการณ์ปิดและกิจกรรมที่ปิดไปแล้ว ถึงคราวที่เราฟังเหตุการณ์การปิดกล่องโต้ตอบแล้ว
คราวนี้ใช้ตัวสังเกตการเปลี่ยนแปลงที่สร้างขึ้นเพื่อดูแอตทริบิวต์ของกล่องโต้ตอบ
…
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 ของผู้สังเกตการเปลี่ยนแปลงเมื่อมีการเปลี่ยนแอตทริบิวต์กล่องโต้ตอบ โดยแสดงรายการการเปลี่ยนแปลงเป็นอาร์เรย์ ทำซ้ำการเปลี่ยนแปลงแอตทริบิวต์โดยรอให้ attributeName
เปิดขึ้น ถัดไป ให้ตรวจสอบว่าองค์ประกอบมีแอตทริบิวต์หรือไม่ ซึ่งจะแจ้งให้ทราบว่ากล่องโต้ตอบเปิดอยู่หรือไม่ หากเปิดแล้ว ให้นำแอตทริบิวต์ inert
ออก ตั้งโฟกัสเป็นองค์ประกอบที่ขอ autofocus
หรือองค์ประกอบ button
แรกที่พบในกล่องโต้ตอบ สุดท้าย ให้ส่งกิจกรรมเปิดทันที รอให้ภาพเคลื่อนไหวจบแล้วจึงส่งกิจกรรมที่เปิด
การเพิ่มกิจกรรมที่นำออก
ในแอปพลิเคชันหน้าเว็บเดียว กล่องโต้ตอบมักจะถูกเพิ่มและนำออกตามเส้นทางหรือความต้องการและสถานะอื่นๆ ของแอปพลิเคชัน การล้างข้อมูลเหตุการณ์หรือข้อมูลเมื่อนำกล่องโต้ตอบออกอาจเป็นประโยชน์
แต่จะทำได้กับผู้สังเกตการเปลี่ยนแปลงอีกคน คราวนี้ แทนที่จะสังเกตแอตทริบิวต์ในองค์ประกอบกล่องโต้ตอบ เราจะสังเกตองค์ประกอบย่อยขององค์ประกอบเนื้อหา และคอยสังเกตองค์ประกอบกล่องโต้ตอบที่จะถูกนำออก
…
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)
}
})
})
})
ระบบจะเรียกใช้ Callback ของผู้สังเกตการเปลี่ยนแปลงเมื่อมีการเพิ่มหรือนำเด็กออกจากเนื้อความของเอกสาร การเปลี่ยนแปลงที่เฉพาะเจาะจงซึ่งกําลังเฝ้าดูอยู่เป็นของ 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)
ต่อไปนี้เป็นตัวอย่าง 2 ตัวอย่างของการจัดการเหตุการณ์เหล่านั้น
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
: พารามิเตอร์นี้มีสตริงปิดที่ส่งผ่านเมื่อมีการเรียกเหตุการณ์ close()
ในกล่องโต้ตอบ ในเหตุการณ์ dialogClosed
จําเป็นต้องทราบว่ากล่องโต้ตอบปิด ยกเลิก หรือยืนยันหรือไม่ หากได้รับการยืนยันแล้ว สคริปต์จะจับค่าของฟอร์มและรีเซ็ตฟอร์ม การรีเซ็ตจะมีประโยชน์ เช่น เมื่อกล่องโต้ตอบแสดงขึ้นอีกครั้ง กล่องโต้ตอบจะว่างเปล่าและพร้อมสำหรับการส่งใหม่
บทสรุป
ตอนนี้คุณก็รู้แล้วว่าฉันทำท่านั้นได้อย่างไร คุณจะทำยังไงบ้างคะ‽ 🙂
มาเพิ่มความหลากหลายให้กับแนวทางของเราและเรียนรู้วิธีทั้งหมดในการสร้างเนื้อหาบนเว็บกัน
สร้างการสาธิต ลิงก์ทวีตฉัน แล้วฉันจะเพิ่ม ลงในส่วนรีมิกซ์ของชุมชนด้านล่าง
รีมิกซ์ในชุมชน
- @GrimLink พร้อมกล่องโต้ตอบแบบ 3-in-1
- @mikemai2awesome พร้อมรีมิกซ์ดีๆ ที่ไม่เปลี่ยนพร็อพเพอร์ตี้
display
- @geoffrich_ ด้วย Svelte กับ Svelte FLIP ขัดเกลาอย่างสวยงาม
แหล่งข้อมูล
- ซอร์สโค้ดใน GitHub
- รูปโปรไฟล์ Doodle