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…)。