องค์ประกอบที่กำหนดเองช่วยให้คุณสร้างแท็ก HTML ของคุณเองได้ รายการตรวจสอบนี้ครอบคลุมแนวทางปฏิบัติแนะนำเพื่อช่วยคุณสร้างองค์ประกอบที่มีคุณภาพสูง
องค์ประกอบที่กำหนดเองช่วยให้คุณขยาย HTML และกำหนดแท็กของคุณเองได้ เป็น
เป็นฟีเจอร์ที่มีประสิทธิภาพอย่างเหลือเชื่อ แต่อยู่ในระดับต่ำเช่นกัน ซึ่งหมายความว่า
ควรทราบวิธีที่ดีที่สุดในการใช้งานองค์ประกอบของคุณเอง
เพื่อช่วยคุณสร้างประสบการณ์ที่ดีที่สุด เราได้รวบรวมข้อมูลนี้เข้าด้วยกัน
รายการตรวจสอบ ได้แตกลายทุกสิ่งที่เราคิดว่า จำเป็นต่อการเป็น
องค์ประกอบที่กำหนดเองและทำงานได้ดี
เช็กลิสต์
Shadow DOM
สร้างรากเงาเพื่อสรุปรูปแบบ
เพราะเหตุใด
รูปแบบการห่อหุ้มในรากเงาขององค์ประกอบจะช่วยให้มั่นใจได้ว่ารูปแบบนั้นจะทำงาน
ไม่ว่าจะใช้งานอยู่ที่ใด ซึ่งสำคัญมากหากนักพัฒนาแอป
ต้องการวางองค์ประกอบของคุณไว้ภายในรากเงาขององค์ประกอบอื่น ช่วงเวลานี้
ใช้ได้กับองค์ประกอบง่ายๆ เช่น ช่องทำเครื่องหมายหรือปุ่มตัวเลือก อาจจะเป็น
ในกรณีนี้ เนื้อหาเดียวภายในรากเงาของคุณจะเป็นรูปแบบ
ด้วยตนเอง
ตัวอย่าง
<howto-checkbox>
สร้างรากเงาในเครื่องมือสร้าง
เพราะเหตุใด
เครื่องมือสร้างคือเมื่อคุณมีความรู้เฉพาะตัว เกี่ยวกับองค์ประกอบนั้นๆ
ตอนนี้เป็นเวลาที่เหมาะสมในการตั้งค่ารายละเอียดการใช้งานที่คุณไม่ต้องการ
องค์ประกอบที่มีอยู่มากมาย การดำเนินการนี้จะดำเนินการในการเรียกกลับในภายหลัง เช่น
connectedCallback
ซึ่งหมายความว่าคุณจะต้องป้องกัน
สถานการณ์ที่องค์ประกอบของคุณถูกแยกออก แล้วแนบกับเอกสารอีกครั้ง
ตัวอย่าง
<howto-checkbox>
วางองค์ประกอบย่อยที่องค์ประกอบสร้างขึ้นลงในรากที่เป็นเงา
เพราะเหตุใด
องค์ประกอบย่อยที่องค์ประกอบสร้างขึ้นเป็นส่วนหนึ่งของการใช้งาน และควรเป็น
ส่วนตัว หากปราศจากการป้องกันของรากที่มืด JavaScript ภายนอกอาจ
และรบกวนเด็กเหล่านี้โดยไม่ได้ตั้งใจ
ตัวอย่าง
<howto-tabs>
ใช้ <slot> เพื่อฉายภาพย่อยของ Light DOM เข้าไปใน Shadow DOM
เพราะเหตุใด
อนุญาตให้ผู้ใช้ของคอมโพเนนต์ระบุเนื้อหาในคอมโพเนนต์เนื่องจากองค์ประกอบย่อย HTML ทำให้คอมโพเนนต์สามารถเขียนได้ง่ายขึ้น เมื่อเบราว์เซอร์ไม่รองรับองค์ประกอบที่กำหนดเอง เนื้อหาที่ซ้อนอยู่จะยังคงใช้งานได้ มองเห็นได้ และเข้าถึงได้
ตัวอย่าง
<howto-tabs>
ตั้งค่ารูปแบบการแสดงผล :host
(เช่น block
,
inline-block
, flex
) ยกเว้นกรณีที่คุณต้องการใช้ค่าเริ่มต้น
inline
เพราะเหตุใด
องค์ประกอบที่กำหนดเองจะเป็น display: inline
โดยค่าเริ่มต้น ดังนั้นการตั้งค่าองค์ประกอบ
width
หรือheight
จะไม่มีผลใดๆ บ่อยครั้ง
เป็นเรื่องน่าประหลาดใจสำหรับนักพัฒนาแอปและอาจทำให้เกิดปัญหาเกี่ยวกับ
การจัดวางหน้าเว็บ หากคุณไม่ต้องการจอแสดงผลแบบ inline
ควรกำหนดค่า display
เริ่มต้นเสมอ
ตัวอย่าง
<howto-checkbox>
เพิ่มรูปแบบการแสดงผล :host
ที่ใช้แอตทริบิวต์ที่ซ่อนอยู่
เพราะเหตุใด
องค์ประกอบที่กําหนดเองซึ่งมีรูปแบบ display
เริ่มต้น เช่น
:host { display: block }
จะลบล้างค่าที่เจาะจงต่ำกว่า
ในตัว
hidden
ซึ่งอาจทำให้คุณประหลาดใจหากคุณต้องการตั้งค่า hidden
ในเอลิเมนต์เพื่อแสดงผล display: none
นอกจากนี้
เป็นรูปแบบ display
เริ่มต้น เพิ่มการสนับสนุนสำหรับ hidden
ด้วย :host([hidden]) { display: none }
ตัวอย่าง
<howto-checkbox>
แอตทริบิวต์และพร็อพเพอร์ตี้
อย่าลบล้างแอตทริบิวต์ร่วมที่ผู้เขียนตั้งไว้
เพราะเหตุใด
แอตทริบิวต์ร่วมคือแอตทริบิวต์ที่มีอยู่ในองค์ประกอบ HTML ทั้งหมด ใช้บ้าง
เช่น tabindex
และ role
องค์ประกอบที่กำหนดเอง
อาจต้องการตั้งค่า tabindex
เริ่มต้นให้เป็น 0 เพื่อให้เป็นแป้นพิมพ์
โฟกัสได้ แต่คุณควรตรวจสอบก่อนเสมอเพื่อดูว่านักพัฒนาที่ใช้
องค์ประกอบตั้งค่าเป็นค่าอื่น เช่น หากการตั้งค่า
tabindex
ต่อ -1 นั่นเป็นสัญญาณว่าไม่ต้องการ
เป็นแบบอินเทอร์แอกทีฟ
ตัวอย่าง
<howto-checkbox>
ซึ่งอธิบายเพิ่มเติมใน
อย่าลบล้างผู้เขียนหน้าเว็บ
ยอมรับข้อมูลพื้นฐาน (สตริง ตัวเลข บูลีน) เป็นแอตทริบิวต์อย่างใดอย่างหนึ่งเสมอ
หรือเว็บไซต์
เพราะเหตุใด
องค์ประกอบที่กำหนดเอง เช่น องค์ประกอบที่มีมาในตัว ควรสามารถกำหนดค่าได้
สามารถส่งการกำหนดค่าได้แบบประกาศ ผ่านแอตทริบิวต์ หรือส่ง
ผ่านพร็อพเพอร์ตี้ JavaScript โดยหลักการแล้ว แอตทริบิวต์ทุกรายการควรลิงก์กับ
พร็อพเพอร์ตี้ที่เกี่ยวข้อง
ตัวอย่าง
<howto-checkbox>
พยายามซิงค์แอตทริบิวต์และพร็อพเพอร์ตี้ข้อมูลแบบดั้งเดิม โดยจะแสดงข้อมูลจาก
พร็อพเพอร์ตี้เป็นแอตทริบิวต์ และในทางกลับกันด้วย
เพราะเหตุใด
คุณไม่มีทางทราบว่าผู้ใช้จะโต้ตอบกับองค์ประกอบของคุณอย่างไร โดยอาจ
ตั้งค่าพร็อพเพอร์ตี้ใน JavaScript จากนั้นก็จะอ่านค่านั้น
โดยใช้ API เช่น getAttribute()
หากทุกแอตทริบิวต์มี
ที่สอดคล้องกันและทั้งสองแบบ จะช่วยให้คุณสามารถ
ทำงานกับองค์ประกอบของคุณได้ กล่าวคือ การโทร
setAttribute('foo', value)
ควรตั้งค่า
foo
พร็อพเพอร์ตี้และในทางกลับกันด้วย แต่แน่นอนว่ามีข้อยกเว้น
ด้วยกฎนี้ คุณไม่ควรแสดงพร็อพเพอร์ตี้ความถี่สูง เช่น
currentTime
ในวิดีโอเพลเยอร์ โปรดใช้วิจารณญาณที่ดีที่สุด หาก
ดูเหมือนว่าผู้ใช้จะโต้ตอบกับพร็อพเพอร์ตี้หรือแอตทริบิวต์ และ
การสะท้อนความคิดนั้นไม่ใช่เรื่องยุ่งยาก ดังนั้น การทำเช่นนั้นจึงไม่ใช่เรื่องยุ่งยาก
ตัวอย่าง
<howto-checkbox>
ซึ่งอธิบายเพิ่มเติมใน
หลีกเลี่ยงปัญหาการใช้งานซ้ำ
พยายามยอมรับเฉพาะข้อมูลแบบสมบูรณ์ (ออบเจ็กต์ อาร์เรย์) เป็นพร็อพเพอร์ตี้
เพราะเหตุใด
กล่าวโดยทั่วไปคือ ไม่มีตัวอย่างองค์ประกอบ HTML ในตัวที่
ยอมรับข้อมูลสมบูรณ์ (ออบเจ็กต์และอาร์เรย์ JavaScript ธรรมดา) ผ่าน
แต่จะยอมรับข้อมูลแบบสมบูรณ์แทนผ่านการเรียกเมธอดหรือ
พร็อพเพอร์ตี้ มีข้อเสียที่เห็นได้ชัดอยู่ 2-3 ข้อในการยอมรับข้อมูลอย่างละเอียด
แอตทริบิวต์: การจัดชุดวัตถุขนาดใหญ่ไปยังสตริงอาจมีค่าใช้จ่ายสูง และ
การอ้างอิงออบเจ็กต์จะหายไปในกระบวนการกำหนดสตริงนี้ สำหรับ
ตัวอย่างเช่น หากคุณกำหนดเป็นสตริงให้กับออบเจ็กต์ที่มีการอ้างอิงไปยังออบเจ็กต์อื่น
หรือโหนด DOM การอ้างอิงเหล่านั้นจะหายไป
ไม่แสดงพร็อพเพอร์ตี้ข้อมูลแบบสมบูรณ์ในแอตทริบิวต์
เพราะเหตุใด
การใช้คุณสมบัติข้อมูลอย่างละเอียดกับแอตทริบิวต์นั้นมีค่าใช้จ่ายสูงโดยไม่จำเป็น
ต้องมีการทำให้เป็นอนุกรมและดีซีเรียลไลซ์ออบเจ็กต์ JavaScript เดียวกัน ยกเว้น
คุณมีกรณีการใช้งานที่ตอบได้ด้วยฟีเจอร์นี้เท่านั้น
ที่ควรหลีกเลี่ยง
ลองตรวจหาพร็อพเพอร์ตี้ที่อาจตั้งค่าไว้ก่อนหน้าองค์ประกอบ
อัปเกรดแล้ว
เพราะเหตุใด
นักพัฒนาซอฟต์แวร์ที่ใช้องค์ประกอบของคุณอาจพยายามตั้งค่าพร็อพเพอร์ตี้ในองค์ประกอบ
ก่อนที่จะมีการโหลดคำจำกัดความ โดยเฉพาะอย่างยิ่งหาก
นักพัฒนาซอฟต์แวร์ใช้เฟรมเวิร์กที่จัดการคอมโพเนนต์การโหลดและประทับตราองค์ประกอบ
กับหน้า และเชื่อมโยงพร็อพเพอร์ตี้กับโมเดล
ตัวอย่าง
<howto-checkbox>
อธิบายเพิ่มเติมใน
ทำให้พร็อพเพอร์ตี้เป็นแบบ Lazy Loading
ห้ามใช้ชั้นเรียนด้วยตนเอง
เพราะเหตุใด
องค์ประกอบที่ต้องแสดงสถานะของตัวเองควรดำเนินการดังกล่าวโดยใช้แอตทริบิวต์
โดยทั่วไปจะถือว่าแอตทริบิวต์ class
เป็นของ
นักพัฒนาซอฟต์แวร์ที่ใช้องค์ประกอบของคุณ และการเขียนถึงด้วยตนเองโดยไม่เจตนา
กระทืบเท้าที่ชั้นเรียนของนักพัฒนาซอฟต์แวร์
กิจกรรม
ส่งเหตุการณ์เพื่อตอบสนองต่อกิจกรรมของคอมโพเนนต์ภายใน
เพราะเหตุใด
คอมโพเนนต์อาจมีคุณสมบัติที่เปลี่ยนไปตามกิจกรรมที่
มีแค่คอมโพเนนต์ที่ทราบ เช่น ถ้าตัวจับเวลาหรือภาพเคลื่อนไหว
หรือทรัพยากรโหลดเสร็จแล้ว การเผยแพร่กิจกรรมจะช่วยได้
ตอบสนองต่อการเปลี่ยนแปลงเหล่านี้เพื่อแจ้งโฮสต์ว่าสถานะของคอมโพเนนต์คือ
แตกต่างกัน
อย่าส่งเหตุการณ์ตามการตั้งค่าพร็อพเพอร์ตี้ของโฮสต์ (ลงด้านล่าง)
โฟลว์ข้อมูล)
เพราะเหตุใด
การส่งเหตุการณ์เพื่อตอบสนองต่อการตั้งค่าโฮสต์นั้นถือเป็นสิ่งที่ไม่จำเป็น
(โฮสต์ทราบสถานะปัจจุบันของเนื่องจากเพิ่งตั้งค่า) การส่งกิจกรรม
ในการตอบกลับการตั้งค่าโฮสต์ พร็อพเพอร์ตี้อาจทําให้เกิดการวนซ้ำกับข้อมูลที่ไม่สิ้นสุด
ระบบการผูก
ตัวอย่าง
<howto-checkbox>
วิดีโออธิบาย
อย่าลบล้างผู้เขียนหน้าเว็บ
เป็นไปได้ว่านักพัฒนาซอฟต์แวร์ที่ใช้เอลิเมนต์ของคุณอาจต้องการลบล้าง
สถานะเริ่มต้น ตัวอย่างเช่น การเปลี่ยน ARIA role
หรือความสามารถในการโฟกัสด้วย
tabindex
ตรวจสอบว่ามีการตั้งค่าเหล่านี้และแอตทริบิวต์ร่วมอื่นๆ หรือไม่
ก่อนที่จะนำค่าของคุณเองไปใช้
connectedCallback () {
if ( ! this . hasAttribute ( 'role '))
this . setAttribute ( 'role ', 'checkbox ');
if ( ! this . hasAttribute ( 'tabindex '))
this . setAttribute ( 'tabindex ', 0 );
ทำให้พร็อพเพอร์ตี้เป็นแบบ Lazy Loading
นักพัฒนาซอฟต์แวร์อาจพยายามตั้งค่าพร็อพเพอร์ตี้ในองค์ประกอบก่อน
โหลดคำจำกัดความแล้ว โดยเฉพาะอย่างยิ่งหากนักพัฒนาแอปใช้
เฟรมเวิร์กที่จัดการคอมโพเนนต์การโหลด การแทรกโค้ดลงในหน้า และ
ก็เชื่อมโยงพร็อพเพอร์ตี้กับโมเดล
ในตัวอย่างต่อไปนี้ Angular จะเชื่อมโยง
isChecked
เป็นพร็อพเพอร์ตี้ checked
ของช่องทำเครื่องหมาย หากคำจำกัดความของ
มีการโหลดช่องทำเครื่องหมายวิธีการแบบ Lazy Loading แล้ว Angular อาจพยายามตั้งค่า
พร็อพเพอร์ตี้ที่ทำเครื่องหมายก่อนที่องค์ประกอบจะอัปเกรด
<howto-checkbox [checked]="defaults.isChecked"></howto-checkbox>
องค์ประกอบที่กำหนดเองควรจัดการสถานการณ์นี้ได้ โดยตรวจสอบว่ามีพร็อพเพอร์ตี้ใด
ได้รับการตั้งค่าในอินสแตนซ์แล้ว <howto-checkbox>
แสดงรูปแบบนี้โดยใช้วิธีการที่เรียกว่า _upgradeProperty()
connectedCallback () {
...
this . _upgradeProperty ( 'checked ');
}
_upgradeProperty ( prop ) {
if ( this . hasOwnProperty ( prop )) {
let value = this [ prop ];
delete this [ prop ];
this [ prop ] = value ;
}
}
_upgradeProperty()
จะบันทึกค่าจากอินสแตนซ์ที่ไม่ได้อัปเกรดและลบ
พร็อพเพอร์ตี้ เพื่อไม่ให้เป็นเงาของตัวตั้งค่าพร็อพเพอร์ตี้ขององค์ประกอบที่กำหนดเอง
วิธีนี้จะทำให้เมื่อคำจำกัดความขององค์ประกอบโหลดในที่สุด ก็จะสามารถ
เพื่อแสดงสถานะที่ถูกต้อง
หลีกเลี่ยงปัญหาเกี่ยวกับการเข้าชมซ้ำ
อยากใช้ attributeChangedCallback()
เพื่อแสดงสถานะต่อ
พร็อพเพอร์ตี้ที่สำคัญ เช่น
// When the [checked] attribute changes, set the checked property to match.
attributeChangedCallback ( name , oldValue , newValue ) {
if ( name === 'checked ')
this . checked = newValue ;
}
แต่วิธีนี้สามารถสร้างการวนซ้ำที่ไม่สิ้นสุดได้หากตัวตั้งค่าคุณสมบัติสะท้อนให้เห็นถึง
แอตทริบิวต์
set checked ( value ) {
const isChecked = Boolean ( value );
if ( isChecked )
// OOPS! This will cause an infinite loop because it triggers the
// attributeChangedCallback() which then sets this property again.
this . setAttribute ( 'checked ', '');
else
this . removeAttribute ( 'checked ');
}
อีกวิธีหนึ่งคืออนุญาตให้ตัวตั้งค่าพร็อพเพอร์ตี้แสดงผลต่อแอตทริบิวต์ และ
ให้ Getter กำหนดค่าตามแอตทริบิวต์
set checked ( value ) {
const isChecked = Boolean ( value );
if ( isChecked )
this . setAttribute ( 'checked ', '');
else
this . removeAttribute ( 'checked ');
}
get checked () {
return this . hasAttribute ( 'checked ');
}
ในตัวอย่างนี้ การเพิ่มหรือนำแอตทริบิวต์ออกจะเป็นการตั้งค่าพร็อพเพอร์ตี้ด้วย
สุดท้าย คุณใช้ attributeChangedCallback()
เพื่อจัดการผลข้างเคียงได้
เช่น ใช้สถานะ ARIA
attributeChangedCallback ( name , oldValue , newValue ) {
const hasValue = newValue !== null ;
switch ( name ) {
case 'checked ':
// Note the attributeChangedCallback is only handling the *side effects*
// of setting the attribute.
this . setAttribute ( 'aria - checked ', hasValue );
break ;
...
}
}