浏览器如何处理<template>标签和<div>标签的区别

9
我一直在阅读关于<template>标签的文档,但似乎无法理解它与仅使用<div>(具有display: none;)的区别。
文档链接:template tag <template>示例
<template id="productrow">
  <tr>
    <td class="record"></td>
    <td></td>
  </tr>
</template>

VS <div> example

<div id="productrow" style="display: none">
  <tr>
    <td class="record"></td>
    <td></td>
  </tr>
</div>
  1. 在低层次上,浏览器如何不同地处理这两个示例?
  2. 是否有某些JS方法或HTML属性是不同的或不可用的?

PS:我知道浏览器兼容性存在差异。


4
模板可以放在head中,而div则不能。 - Daniel A. White
1
div 还有 align,而 template 则有 content - Daniel A. White
5
此外,<template> 可以容纳在 div 中无效的元素(就像您的示例中一样)。 - Teemu
1
你在询问低级别的问题,但从高级别的角度来看:<template> 允许编写良好语义化的代码,因为它清楚地表明这不是一个常规的页面元素。 - John Ellmore
3个回答

14
考虑:
<template>
  <style>
    body: { background-color: black; }
  </style>
  <script>
    alert('hello');
  </script>
  <audio src="alert.wav" autoplay></audio>
</template>

而且:

<div style="display: none;">
  <style>
    body: { background-color: black; }
  </style>
  <script>
    alert('hello');
  </script>
  <audio src="alert.wav" autoplay></audio>
</div>

当浏览器渲染它们时,这两个示例会表现相同吗?(剧透:不会。)

然而,要回答你的具体问题:

  1. 从低层面来说,浏览器如何处理这两个示例的差异?

首先,<template> 中的 HTML 不会成为 <template> 的子节点的 DOM 元素。它成为一个“惰性”的 DocumentFragment(间接地;这是一种简化),在那里它们存在为节点但不会“做”任何事情,就像上面的示例。

除了是“惰性”的外,模板内容没有“符合性要求”。你上面的 <tr> 示例很好。看看这里发生了什么:

const template = document.querySelector('template');
const div = document.querySelector('div');

console.log('template.innerHTML is', template.innerHTML);
console.log('div.innerHTML is', div.innerHTML);
<template>
  <tr>
    <td class="record"></td>
    <td></td>
  </tr>
</template>

<div style="display: none">
  <tr>
    <td class="record"></td>
    <td></td>
  </tr>
</div>

在常规文档中,<tr>不能作为<div>的子元素存在,因此浏览器会将其删除。但在<template>中不存在这种要求。同样,对于<div style="{{myStyle}}">,浏览器在文档中会丢弃style属性,因为它的值无效;但在<template>中不会这样做。这就是<template>在模板化方面使用的原因。

如果您想了解更多关于<template>如何呈现的内容,我建议阅读HTML规范中相关部分。虽然有些难以理解,但您可以从中学到很多东西。

<template>元素具有content属性,该属性指向上述讨论的DocumentFragment。


当然,你应该指出评论中提到的其他差异,虽然这是正确的。 - idmean
2
display: none会导致内容不被添加到DOM树中吗?还是仍然被渲染但不在页面上“物理”存在? - PrivatMamtora
3
"display: none" 只影响元素的外观,但它仍参与文档对象模型(DOM)的构建。 - Jordan Running

4

<template> 内部的元素无法被JS中的任何选择器找到,因此您无法意外地找到它们并提取它们,您必须使用 HTMLTemplateElementcontent 属性来进行提取,例如:

var clone = document.importNode(templateElement.content, true);

此外,每个 <style><audio>/<video>/...<script> 标签都会在页面加载时被解析,但只有当你将其克隆到主 DOM 中后才会运行。


2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接