<template>: 內容模板元素

基線 廣泛可用

此功能已建立良好,並在許多裝置和瀏覽器版本上都能正常工作。它自 2015 年 11 月.

<template> HTML 元素充當用於儲存 HTML 片段的機制,這些片段可以稍後透過 JavaScript 使用,也可以立即生成到影子 DOM 中。

屬性

此元素包含 全域性屬性

shadowrootmode

為父元素建立 影子根。它是 Element.attachShadow() 方法的宣告式版本,並接受相同的 列舉 值。

open

為 JavaScript 公開內部影子根 DOM(建議用於大多數用例)。

closed

將內部影子根 DOM 隱藏在 JavaScript 之外。

注意:HTML 解析器在 DOM 中為第一個 <template> 建立一個 ShadowRoot 物件,該物件具有設定為允許值的屬性。如果屬性未設定或未設定為允許值 - 或者如果在同一個父節點中已宣告式建立了 ShadowRoot,則將構建一個 HTMLTemplateElement。解析後,HTMLTemplateElement 無法隨後更改為影子根,例如,透過設定 HTMLTemplateElement.shadowRootMode

注意:你可能會在舊的教程和示例中找到非標準的 shadowroot 屬性,這些屬性過去曾在 Chrome 90-110 中得到支援。此屬性已被刪除,並由標準 shadowrootmode 屬性取代。

shadowrootclonable

將使用此元素建立的 ShadowRootclonable 屬性值設定為 true。如果設定,則使用 Node.cloneNode()Document.importNode() 建立的影子主機(此 <template> 的父元素)的克隆將包含副本中的影子根。

shadowrootdelegatesfocus

將使用此元素建立的 ShadowRootdelegatesFocus 屬性值設定為 true。如果設定了此值,並且選擇了影子樹中的不可聚焦元素,則焦點將委託給樹中的第一個可聚焦元素。預設值為 false

shadowrootserializable 實驗性

將使用此元素建立的 ShadowRootserializable 屬性值設定為 true。如果設定,則可以透過呼叫 Element.getHTML()ShadowRoot.getHTML() 方法(將 options.serializableShadowRoots 引數設定為 true)序列化影子根。預設值為 false

使用說明

使用 <template> 元素主要有兩種方法。

模板文件片段

預設情況下,元素的內容不會被渲染。相應的 HTMLTemplateElement 介面包含一個標準的 content 屬性(沒有等效的 content/markup 屬性)。此 content 屬性是隻讀的,它儲存一個 DocumentFragment,該片段包含由模板表示的 DOM 子樹。此片段可以透過 cloneNode 方法克隆,並插入到 DOM 中。

使用 content 屬性時要小心,因為返回的 DocumentFragment 可能表現出意外的行為。有關更多詳細資訊,請參見下面的 避免 DocumentFragment 陷阱 部分。

宣告式影子 DOM

如果 <template> 元素包含 shadowrootmode 屬性,

如果元素的shadowrootmode屬性具有任何其他值,或者沒有shadowrootmode屬性,解析器會生成一個HTMLTemplateElement。類似地,如果存在多個宣告式影子根,則只有第一個被替換為ShadowRoot - 後續例項被解析為HTMLTemplateElement物件。

示例

生成表格行

首先,我們從示例的 HTML 部分開始。

html
<table id="producttable">
  <thead>
    <tr>
      <td>UPC_Code</td>
      <td>Product_Name</td>
    </tr>
  </thead>
  <tbody>
    <!-- existing data could optionally be included here -->
  </tbody>
</table>

<template id="productrow">
  <tr>
    <td class="record"></td>
    <td></td>
  </tr>
</template>

首先,我們有一個表格,我們將在稍後使用 JavaScript 程式碼將內容插入到其中。然後是模板,它描述了一個表示單個表格行的 HTML 片段的結構。

現在表格已經建立並且模板已定義,我們使用 JavaScript 將行插入到表格中,其中每行都是使用模板作為其基礎構建的。

js
// Test to see if the browser supports the HTML template element by checking
// for the presence of the template element's content attribute.
if ("content" in document.createElement("template")) {
  // Instantiate the table with the existing HTML tbody
  // and the row with the template
  const tbody = document.querySelector("tbody");
  const template = document.querySelector("#productrow");

  // Clone the new row and insert it into the table
  const clone = template.content.cloneNode(true);
  let td = clone.querySelectorAll("td");
  td[0].textContent = "1235646565";
  td[1].textContent = "Stuff";

  tbody.appendChild(clone);

  // Clone the new row and insert it into the table
  const clone2 = template.content.cloneNode(true);
  td = clone2.querySelectorAll("td");
  td[0].textContent = "0384928528";
  td[1].textContent = "Acme Kidney Beans 2";

  tbody.appendChild(clone2);
} else {
  // Find another way to add the rows to the table because
  // the HTML template element is not supported.
}

結果是原始 HTML 表格,透過 JavaScript 向其追加了兩行。

實現宣告式影子 DOM

在本例中,在標記的開頭包含了一個隱藏的支援警告。如果瀏覽器不支援shadowrootmode屬性,則該警告將在稍後透過 JavaScript 設定為顯示。接下來,有兩個<article>元素,每個元素都包含巢狀的<style>元素,它們的行為不同。第一個<style>元素對整個文件是全域性的。第二個元素被限定在<template>元素所在位置生成的影子根中,因為存在shadowrootmode屬性。

html
<p hidden>
  ⛔ Your browser doesn't support <code>shadowrootmode</code> attribute yet.
</p>
<article>
  <style>
    p {
      padding: 8px;
      background-color: wheat;
    }
  </style>
  <p>I'm in the DOM.</p>
</article>
<article>
  <template shadowrootmode="open">
    <style>
      p {
        padding: 8px;
        background-color: plum;
      }
    </style>
    <p>I'm in the shadow DOM.</p>
  </template>
</article>
js
const isShadowRootModeSupported =
  HTMLTemplateElement.prototype.hasOwnProperty("shadowRootMode");

document
  .querySelector("p[hidden]")
  .toggleAttribute("hidden", isShadowRootModeSupported);

具有委託焦點的宣告式影子 DOM

此示例演示瞭如何將shadowrootdelegatesfocus應用於宣告式建立的影子根,以及這種操作對焦點的影響。

程式碼首先使用帶有shadowrootmode屬性的<template>元素,在<div>元素內宣告一個影子根。這將顯示一個不可聚焦的包含文字的<div>元素和一個可聚焦的<input>元素。它還使用 CSS 來設定具有:focus的元素的樣式為藍色,並設定宿主元素的常規樣式。

html
<div>
  <template shadowrootmode="open">
    <style>
      :host {
        display: block;
        border: 1px dotted black;
        padding: 10px;
        margin: 10px;
      }
      :focus {
        outline: 2px solid blue;
      }
    </style>
    <div>Clickable Shadow DOM text</div>
    <input type="text" placeholder="Input inside Shadow DOM" />
  </template>
</div>

第二個程式碼塊與之相同,除了它設定了shadowrootdelegatesfocus屬性,該屬性會將焦點委託給樹中的第一個可聚焦元素,如果樹中選擇了不可聚焦元素。

html
<div>
  <template shadowrootmode="open" shadowrootdelegatesfocus>
    <style>
      :host {
        display: block;
        border: 1px dotted black;
        padding: 10px;
        margin: 10px;
      }
      :focus {
        outline: 2px solid blue;
      }
    </style>
    <div>Clickable Shadow DOM text</div>
    <input type="text" placeholder="Input inside Shadow DOM" />
  </template>
</div>

最後,我們使用以下 CSS 為父<div>元素應用綠色-黃色的邊框,當它獲得焦點時。

css
div:focus {
  border: 2px solid red;
}

結果如下所示。當 HTML 首次渲染時,元素沒有樣式,如第一張圖片所示。對於沒有設定shadowrootdelegatesfocus的影子根,您可以點選除<input>以外的任何地方,焦點都不會改變(如果選擇<input>元素,它看起來就像第二張圖片)。

Screenshot of code with no focus set

對於設定了shadowrootdelegatesfocus的影子根,點選文字(不可聚焦)會選擇<input>元素,因為它是樹中的第一個可聚焦元素。這也使父元素獲得焦點,如下所示。

Screenshot of the code where the element has focus

避免 DocumentFragment 陷阱

當傳遞DocumentFragment值時,Node.appendChild和類似方法僅將該值的子節點移動到目標節點。因此,通常最好將事件處理程式附加到DocumentFragment的子節點,而不是附加到DocumentFragment本身。

考慮以下 HTML 和 JavaScript

HTML

html
<div id="container"></div>

<template id="template">
  <div>Click me</div>
</template>

JavaScript

js
const container = document.getElementById("container");
const template = document.getElementById("template");

function clickHandler(event) {
  event.target.append(" — Clicked this div");
}

const firstClone = template.content.cloneNode(true);
firstClone.addEventListener("click", clickHandler);
container.appendChild(firstClone);

const secondClone = template.content.cloneNode(true);
secondClone.children[0].addEventListener("click", clickHandler);
container.appendChild(secondClone);

結果

由於firstClone是一個DocumentFragment,因此呼叫appendChild時,只有它的子節點會被新增到container中;firstClone的事件處理程式不會被複制。相反,由於事件處理程式被新增到secondClone的第一個子節點,因此呼叫appendChild時事件處理程式會被複制,點選它會像預期的那樣工作。

技術摘要

內容類別 元資料內容流內容短語內容指令碼支援元素
允許的內容 無限制
標籤省略 沒有,起始標籤和結束標籤都是必需的。
允許的父元素 任何接受元資料內容短語內容指令碼支援元素的元素。還允許作為<colgroup>元素的子元素,該元素沒有span屬性。
隱式 ARIA 角色 沒有相應的角色
允許的 ARIA 角色 不允許使用role
DOM 介面 HTMLTemplateElement

規範

規範
HTML 標準
# the-template-element

瀏覽器相容性

BCD 表格僅在瀏覽器中載入

另請參見