使用 Shadow DOM

Lit 元件使用 shadow DOM 來封裝它們的 DOM。Shadow DOM 提供了一種將獨立且封裝的 DOM 樹新增至元素的方法。DOM 封裝是解鎖與頁面上運作的任何其他程式碼(包括其他 Web 元件或 Lit 元件)互通性的關鍵。

Shadow DOM 提供三個優點

  • DOM 範圍設定。像 document.querySelector 這樣的 DOM API 不會找到元件 shadow DOM 中的元素,因此全域腳本更難意外地中斷您的元件。
  • 樣式範圍設定。您可以為您的 shadow DOM 撰寫封裝的樣式,這些樣式不會影響 DOM 樹的其餘部分。
  • 組合。元件的 shadow 根(包含其內部 DOM)與元件的子元素分離。您可以選擇如何在元件的內部 DOM 中渲染子元素。

有關 shadow DOM 的詳細資訊

較舊的瀏覽器。 在原生 shadow DOM 不可用的較舊瀏覽器上,可以使用 web components polyfills。請注意,Lit 的 polyfill-support 模組必須與 web components polyfills 一起載入。請參閱 傳統瀏覽器的需求 以了解詳細資訊。

Lit 將元件渲染到其 renderRoot,預設情況下是 shadow 根。若要尋找內部元素,您可以使用 DOM 查詢 API,例如 this.renderRoot.querySelector()

renderRoot 應始終為 shadow 根或元素,它們共享類似 .querySelectorAll().children 的 API。

您可以在元件初始渲染之後(例如,在 firstUpdated 中)查詢內部 DOM,或使用 getter 模式

LitElement 提供一組裝飾器,可提供定義此類 getter 的簡寫方式。

@query@queryAll@queryAsync 裝飾器都提供了一種便捷的方式來存取內部元件 DOM 中的節點。

使用裝飾器。 裝飾器是一個提議的 JavaScript 功能,因此您需要使用像 Babel 或 TypeScript 這樣的編譯器來使用裝飾器。請參閱 使用裝飾器 以了解詳細資訊。

修改類別屬性,將其變成一個 getter,該 getter 會從渲染根傳回一個節點。當為 true 時,可選的第二個參數僅執行一次 DOM 查詢並快取結果。當被查詢的節點不會更改時,這可以用作效能最佳化。

此裝飾器等效於

query 相同,但傳回所有相符的節點,而不是單個節點。它等效於呼叫 querySelectorAll

在此,_divs 會傳回模板中的兩個 <div> 元素。對於 TypeScript,@queryAll 屬性的類型為 NodeListOf<HTMLElement>。如果您確切知道要檢索哪種節點,則類型可以更具體

buttons 後面的驚嘆號 (!) 是 TypeScript 的 非空斷言運算符。它會告訴編譯器將 buttons 視為始終已定義,而不是 nullundefined

@query 類似,但它不是直接傳回節點,而是傳回一個 Promise,該 Promise 在任何待處理的元素渲染完成後解析為該節點。程式碼可以使用它,而不是等待 updateComplete promise。

舉例來說,如果 @queryAsync 傳回的節點可能會因另一個屬性變更而變更,則此功能很有用。

您的元件可以接受子元素(如 <ul> 元素可以有 <li> 子元素)。

預設情況下,如果元素有 shadow 樹,則其子元素根本不會渲染。

若要渲染子元素,您的範本需要包含一個或多個 <slot> 元素,它們充當子節點的預留位置。

若要渲染元素的子元素,請在元素的範本中為它們建立一個 <slot>。子元素並未在 DOM 樹中移動,但它們的渲染就像它們是 <slot> 的子元素一樣。例如

若要將子元素指派給特定 slot,請確保子元素的 slot 屬性與 slot 的 name 屬性相符

  • 具名 slots 僅接受具有相符 slot 屬性的子元素。

    例如,<slot name="one"></slot> 僅接受具有屬性 slot="one" 的子元素。

  • 具有 slot 屬性的子元素只會渲染到具有相符 name 屬性的 slot 中。

    例如,<p slot="one">...</p> 只會放置在 <slot name="one"></slot> 中。

您可以為 slot 指定回退內容。當沒有子元素指派給 slot 時,會顯示回退內容。

渲染回退內容。 如果有任何子節點指派給 slot,則不會渲染其回退內容。沒有名稱的預設 slot 接受任何子節點。即使唯一指派的節點是包含空白字元的文字節點,它也不會渲染回退內容,例如 <example-element> </example-element>。當使用 Lit 表達式作為自訂元素的子元素時,請確保在適當的時候使用不渲染的值,以便渲染任何 slot 回退內容。請參閱 移除子內容 以了解詳細資訊。

若要存取 shadow 根中指派給 slots 的子元素,您可以使用標準的 slot.assignedNodesslot.assignedElements 方法和 slotchange 事件。

例如,您可以建立一個 getter 來存取特定 slot 的已指派元素

您也可以使用 slotchange 事件,以便在指派的節點變更時採取動作。以下範例會擷取所有 slotted 子元素的文字內容。

如需詳細資訊,請參閱 MDN 上的 HTMLSlotElement

@queryAssignedElements 和 @queryAssignedNodes 裝飾器

“@queryAssignedElements 和 @queryAssignedNodes 裝飾器” 的永久連結

@queryAssignedElements@queryAssignedNodes 會將類別屬性轉換為 getter,該 getter 會傳回分別在元件 shadow 樹中給定 slot 上呼叫 slot.assignedElementsslot.assignedNodes 的結果。使用這些來查詢指派給給定 slot 的元素或節點。

兩者都接受具有以下屬性的可選物件

屬性描述
flatten布林值,指定是否要將指定的節點扁平化,方法是將任何子 <slot> 元素替換為其指定的節點。
slot插槽名稱,指定要查詢的插槽。保留為未定義則選取預設插槽。
selector(僅限 queryAssignedElements如果指定,則僅傳回符合此 CSS 選擇器的指定元素。

決定要使用哪個裝飾器取決於您要查詢指定給插槽的文字節點,還是僅查詢元素節點。此決定取決於您的使用案例。

使用裝飾器。 裝飾器是一個提議的 JavaScript 功能,因此您需要使用像 Babel 或 TypeScript 這樣的編譯器來使用裝飾器。請參閱 使用裝飾器 以了解詳細資訊。

上面的範例等同於下列程式碼

每個 Lit 元件都有一個渲染根,這是一個 DOM 節點,作為其內部 DOM 的容器。

預設情況下,LitElement 會建立一個開放的 shadowRoot 並在其中渲染,產生下列 DOM 結構

有兩種方法可以自訂 LitElement 使用的渲染根

  • 設定 shadowRootOptions
  • 實作 createRenderRoot 方法。

自訂渲染根最簡單的方法是設定 shadowRootOptions 靜態屬性。createRenderRoot 的預設實作會在建立元件的 shadow root 時,將 shadowRootOptions 作為選項引數傳遞給 attachShadow。它可以設定為自訂 ShadowRootInit 字典中允許的任何選項,例如 modedelegatesFocus

請參閱 MDN 上的 Element.attachShadow() 以取得更多資訊。

createRenderRoot 的預設實作會建立一個開放的 shadow root,並將 static styles 類別欄位中設定的任何樣式新增至其中。如需樣式的詳細資訊,請參閱樣式

若要自訂元件的渲染根,請實作 createRenderRoot 並傳回您希望範本渲染到的節點。

例如,若要將範本渲染到主 DOM 樹狀結構中作為元素的子節點,請實作 createRenderRoot 並傳回 this

渲染到子節點中。 一般不建議渲染到子節點而非 shadow DOM 中。您的元素將無法存取 DOM 或樣式範圍,並且無法將元素組合到其內部 DOM 中。