องค์ประกอบที่กำหนดเองช่วยให้คุณสร้างแท็ก 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;
...
}
}