你可以使用自訂元素,建構自己的 HTML 標記。這份檢查清單涵蓋了建構高品質元素的最佳做法。
自訂元素可讓您擴充 HTML 及定義自己的標記。他們是
功能非常強大,但是等級很低
請務必明確指出導入自己的元素最佳方式
為了協助您創造最佳體驗,我們整理了以下內容
檢查清單。它會詳細列出我們認為
自訂元素的行為良好。
檢查清單
陰影 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 中設定屬性,然後預期讀取該值
透過 getAttribute() 等 API如果每項屬性都有
資源與資源相對應
使用者與元素搭配運作也就是呼叫
setAttribute('foo', value) 也應設定對應的
foo 屬性,反之亦然。當然,
此規則。請勿反映頻率高的屬性,例如:
currentTime 。請善用判斷力。如果是
似乎會與資源或屬性互動
沒辦法反映這一點
|
範例 |
<howto-checkbox> 元素。詳細說明請參閱
避免重複性問題。
|
請僅接受多媒體資料 (物件、陣列) 做為屬性。
|
為什麼? |
一般來說,不會包含一些內建 HTML 元素的內建範例。
透過其接受豐富的資料 (純文字 JavaScript 物件和陣列)
屬性。是透過方法呼叫或
資源。接受多媒體資料擁有幾項明顯的缺點
屬性:將大型物件序列化為字串可能非常昂貴。
所有物件參照都會在這項字串化程序中遺失。適用對象
例如,如果您將一個物件對應至另一個物件的參照,
或 DOM 節點,這些參照就會遺失
|
請勿將豐富的資料屬性反映至屬性。
|
為什麼? |
將豐富的資料屬性反映到屬性不需花太多錢。
需要對相同的 JavaScript 物件進行序列化與取消序列化作業。除非
您的用途只能透過這項功能解決
務必避免。
|
建議檢查在元素之前已設定的屬性
已升級
|
為什麼? |
使用你的元素的開發人員可能會嘗試在元素上設定屬性
載入其定義之前。如果
開發人員使用的是可處理載入元件的架構,
並將屬性繫結至模型。
|
範例 |
<howto-checkbox> 元素。詳細說明請見
將屬性設為延遲。
|
請勿自行套用類別。
|
為什麼? |
需要表示狀態的元素應使用屬性來表示。
class 屬性通常視為
並自行撰寫文字
開發人員類別簡介
|
活動
分派事件以回應內部元件活動。
|
為什麼? |
您的元件可能有屬性變更,以因應
只有元件知道的知識,例如計時器或動畫
或是資源完成載入有助於調度事件
回應這些變更,並通知主機元件的狀態
也不一樣
|
不要為回應主機設定屬性 (向下) 分派事件
資料流)。
|
為什麼? |
分派事件以回應主機設定時,作業方式不流暢
(由於主機剛設定,主機就知道目前狀態)。分派事件
回應主機設定,可能會導致資料發生無限迴圈
繫結系統
|
範例 |
<howto-checkbox> 元素。
|
釋疑影片
不要覆寫網頁作者
使用元素的開發人員可能會想覆寫某些值
這項動作會抹除機器的記憶體內容
並將虛擬機器重設為初始狀態例如,將 ARIA role
變更為可聚焦性
tabindex
。請確認是否已設定這些和任何其他全域屬性。
才能套用自己的值
connectedCallback() {
if (!this.hasAttribute('role'))
this.setAttribute('role', 'checkbox');
if (!this.hasAttribute('tabindex'))
this.setAttribute('tabindex', 0);
將屬性設為延遲
在元素開始前,開發人員可能會嘗試先設定元素的屬性
定義已載入如果開發人員使用
以及處理載入元件、將元件插入頁面
將屬性與模型繫結至模型中
在下方範例中,Angular 會以宣告方式繫結模型的
設為核取方塊 checked
屬性的 isChecked
屬性。如果
How to-checkbox 會延遲載入,很有可能讓 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()
會從未升級的執行個體中擷取值並刪除
屬性,這樣就不會覆蓋自訂元素本身的屬性 setter。
這樣一來,元素定義最終完全載入後,就能立即
反映正確的狀態
避免重複發生問題
您可能會很想使用 attributeChangedCallback()
將狀態反映為
基礎屬性,例如:
// When the [checked] attribute changes, set the checked property to match.
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'checked')
this.checked = newValue;
}
不過,如果屬性 setter 也反映
屬性。
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');
}
另一種方式是允許屬性 setter 反映屬性
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;
...
}
}