Element: attachShadow() 方法

Baseline 廣泛可用 *

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2020 年 1 月⁩ 起,所有主流瀏覽器均已支援。

* 此特性的某些部分可能存在不同級別的支援。

Element.attachShadow() 方法將一個 Shadow DOM 樹附加到指定的元素,並返回對其 ShadowRoot 的引用。

可以附加 Shadow DOM 的元素

請注意,你不能將 Shadow Root 附加到每種型別的元素上。出於安全原因,有些元素不能擁有 Shadow DOM(例如 <a>)。

以下是你可以附加 Shadow Root 的元素列表:

在一個已經是 Shadow Host 的元素上呼叫此方法

此方法可以在已具有宣告式 Shadow Root的元素上呼叫,前提是指定的模式 mode 與現有模式匹配。在這種情況下,已經存在的 ShadowRoot 將被清除並返回。這允許一些情況,例如,伺服器端渲染已經宣告式地建立了一個 Shadow Root,然後客戶端程式碼嘗試再次附加該根。

否則,在一個已經有 Shadow Root 的元素上呼叫 attachShadow() 將會丟擲異常。

語法

js
attachShadow(options)

引數

options

一個包含以下欄位的物件:

模式

一個字串,指定 Shadow DOM 樹的封裝模式。可以是以下之一:

open

Shadow Root 的元素可以從根外部的 JavaScript 訪問,例如使用 Element.shadowRoot

js
element.attachShadow({ mode: "open" });
element.shadowRoot; // Returns a ShadowRoot obj
closed

禁止從外部 JavaScript 訪問封閉 Shadow Root 的節點。

js
element.attachShadow({ mode: "closed" });
element.shadowRoot; // Returns null
clonable 可選

一個布林值,指定 Shadow Root 是否可克隆:當設定為 true 時,使用 Node.cloneNode()Document.importNode() 克隆的 Shadow Host 將在副本中包含 Shadow Root。其預設值為 false

delegatesFocus 可選

一個布林值,當設定為 true 時,指定緩解自定義元素可聚焦性問題的行為。當 Shadow DOM 中不可聚焦的部分被點選時,第一個可聚焦的部分將獲得焦點,並且 Shadow Host 將獲得任何可用的 :focus 樣式。其預設值為 false

serializable 可選

一個布林值,當設定為 true 時,表示 Shadow Root 是可序列化的。如果設定,Shadow Root 可以透過呼叫 Element.getHTML()ShadowRoot.getHTML() 方法並將 options.serializableShadowRoots 引數設定為 true 來序列化。其預設值為 false

slotAssignment 可選

一個字串,指定 Shadow DOM 樹的插槽分配模式。可以是以下之一:

命名

元素會自動分配到此 Shadow Root 中的 <slot> 元素。宿主中帶有 slot 屬性的任何後代,如果其值與此 Shadow Root 中 <slot>name 屬性匹配,將被分配到該插槽。宿主中沒有 slot 屬性的任何頂級子元素,如果存在沒有 name 屬性的 <slot>(“預設插槽”),將被分配到該插槽。

manual

元素不會自動分配到 <slot> 元素。相反,它們必須透過 HTMLSlotElement.assign() 手動分配。其預設值為 named

返回值

返回一個 ShadowRoot 物件。

異常

NotSupportedError DOMException

當你嘗試將 Shadow Root 附加到以下元素時,可能會丟擲此錯誤:

  • 不在 HTML 名稱空間中或無法附加 Shadow DOM 的元素。
  • 其中元素定義靜態屬性 disabledFeatures 的值已設定為 "shadow"
  • 已經有一個未宣告式建立的 Shadow Root 的元素。
  • 具有宣告式 Shadow Root但指定 mode 與現有模式不匹配的元素。

示例

字數統計自定義元素

以下示例取自我們的 word-count-web-component 演示(也可線上檢視)。你可以看到我們在程式碼中間使用 attachShadow() 建立了一個 Shadow Root,然後將我們自定義元素的內容附加到其中。

js
// Create a class for the element
class WordCount extends HTMLParagraphElement {
  constructor() {
    // Always call super first in constructor
    super();

    // count words in element's parent element
    const wcParent = this.parentNode;

    function countWords(node) {
      const text = node.innerText || node.textContent;
      return text
        .trim()
        .split(/\s+/g)
        .filter((a) => a.trim().length > 0).length;
    }

    const count = `Words: ${countWords(wcParent)}`;

    // Create a shadow root
    const shadow = this.attachShadow({ mode: "open" });

    // Create text node and add word count to it
    const text = document.createElement("span");
    text.textContent = count;

    // Append it to the shadow root
    shadow.appendChild(text);

    // Update count when element content changes
    this.parentNode.addEventListener("input", () => {
      text.textContent = `Words: ${countWords(wcParent)}`;
    });
  }
}

// Define the new element
customElements.define("word-count", WordCount, { extends: "p" });

停用 Shadow DOM

如果元素有一個名為 disabledFeatures 的靜態屬性,它是一個包含字串 "shadow" 的陣列,那麼 attachShadow() 呼叫將丟擲異常。

例如

js
class MyCustomElement extends HTMLElement {
  // Disable shadow DOM for this element.
  static disabledFeatures = ["shadow"];

  constructor() {
    super();
  }

  connectedCallback() {
    // Create a shadow root.
    // This will throw an exception.
    const shadow = this.attachShadow({ mode: "open" });
  }
}

// Define the new element
customElements.define("my-custom-element", MyCustomElement);

規範

規範
DOM
# dom-element-attachshadow

瀏覽器相容性

另見