2022 年 4 月 14 日

範本元素

內建的 <template> 元素用於儲存 HTML 標記範本。瀏覽器會忽略其內容,只檢查語法是否正確,但我們可以在 JavaScript 中存取並使用它來建立其他元素。

理論上,我們可以在 HTML 中的某個地方建立任何不可見的元素,用於儲存 HTML 標記。<template> 有什麼特別之處?

首先,它的內容可以是任何有效的 HTML,即使它通常需要一個適當的封閉標籤。

例如,我們可以放一個表格列 <tr>

<template>
  <tr>
    <td>Contents</td>
  </tr>
</template>

通常,如果我們嘗試將 <tr> 放在例如 <div> 內部,瀏覽器會偵測到無效的 DOM 結構並「修復」它,在周圍加上 <table>。這不是我們想要的。另一方面,<template> 會保留我們放在那裡的內容。

我們也可以將樣式和腳本放入 <template>

<template>
  <style>
    p { font-weight: bold; }
  </style>
  <script>
    alert("Hello");
  </script>
</template>

瀏覽器將 <template> 內容視為「超出文件」:樣式不會套用,腳本不會執行,<video autoplay> 也不會執行,等等。

當我們將內容插入文件時,內容就會變成動態(套用樣式、執行腳本等)。

插入範本

範本內容可以在其 content 屬性中作為 DocumentFragment 取得,這是一種特殊的 DOM 節點。

我們可以將它視為任何其他 DOM 節點,除了有一個特殊屬性:當我們將它插入某處時,會插入它的子節點。

例如

<template id="tmpl">
  <script>
    alert("Hello");
  </script>
  <div class="message">Hello, world!</div>
</template>

<script>
  let elem = document.createElement('div');

  // Clone the template content to reuse it multiple times
  elem.append(tmpl.content.cloneNode(true));

  document.body.append(elem);
  // Now the script from <template> runs
</script>

讓我們使用 <template> 重寫前一章的 Shadow DOM 範例

<template id="tmpl">
  <style> p { font-weight: bold; } </style>
  <p id="message"></p>
</template>

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

<script>
  elem.onclick = function() {
    elem.attachShadow({mode: 'open'});

    elem.shadowRoot.append(tmpl.content.cloneNode(true)); // (*)

    elem.shadowRoot.getElementById('message').innerHTML = "Hello from the shadows!";
  };
</script>

(*) 行中,當我們複製並插入 tmpl.content 時,由於它是 DocumentFragment,會插入它的子節點(<style><p>)。

它們組成了 Shadow DOM

<div id="elem">
  #shadow-root
    <style> p { font-weight: bold; } </style>
    <p id="message"></p>
</div>

摘要

總之

  • <template> 內容可以是任何語法正確的 HTML。
  • <template> 內容被視為「超出文件」,因此它不會影響任何東西。
  • 我們可以從 JavaScript 存取 template.content,複製它以在新的元件中重複使用。

<template> 標籤非常獨特,因為

  • 瀏覽器會檢查其內部的 HTML 語法(與在腳本中使用範本字串相反)。
  • …但仍然允許使用任何頂層 HTML 標籤,即使那些沒有適當包裝器(例如 <tr>)也沒有意義。
  • 當插入文件時,內容會變成互動式:執行腳本、播放 <video autoplay> 等。

<template> 元素沒有任何反覆運算機制、資料繫結或變數替換,但我們可以在它的基礎上實作這些功能。

教學地圖

留言

留言前請先閱讀…
  • 如果你有建議要如何改進 - 請 提交 GitHub 議題 或發起拉取請求,而不是留言。
  • 如果你無法理解文章中的某些內容 - 請說明。
  • 若要插入幾行程式碼,請使用 <code> 標籤,若要插入多行程式碼,請將其包覆在 <pre> 標籤中,若要插入超過 10 行程式碼,請使用沙盒 (plnkrjsbincodepen…)