HTML’s New Template Tag
WhatWG HTML 模板规范
WhatWG HTML 模板规范定义了一个新的 <template>
元素,用于描述一个标准的以 DOM 为基础的方案来实现客户端模板。该模板允许你定义一段可以被转为 HTML 的标记,在页面加载时不生效,但可以在后续进行动态实例化。
本文主要摘抄自第一个参考文档
浏览器兼容
<template>
元素的浏览器兼容性如下图:
要检查浏览器是否支持 <template>
元素,可以创建该DOM元素并检查它是否拥有 content
属性:
1 2 3 4 5 6 7 8 9 10 11 12
| function supportsTemplate() { return 'content' in document.createElement('template'); } let sp = document.querySelector('#support_p'); if (supportsTemplate()) { sp.textContent = '当前浏览器支持 <template> 标签'; sp.style.color = 'green'; } else { sp.textContent = '当前浏览器不支持 <template> 标签'; sp.style.color = 'red'; }
|
模版声明
HTML <template>
元素代表标记中的一个模板,它包含”模板内容”;本质上是一大块的惰性可复制 DOM。 可以把模板想象成一个脚手架的零件,在应用的整个生命周期中你都可以使用(和重用)它。
The template element is used to declare fragments of HTML that can be cloned and inserted in the document by script.
要创建模板的内容,需要声明一些标记并用 <template>
元素将它们包裹起来:
1 2 3 4
| <template id="mytemplate"> <img src="" alt="great image"> <div class="comment"></div> </template>
|
细心的读者可能会注意到那个空图片,这是故意留空的。因为页面加载时不会请求图片,因此就不会产生 404 或控制台错误。我们可以随后动态生成图片的 URL。
模版的特点
用 <template>
来包裹内容为我们提供了几个重要属性:
- 它的内容在激活之前一直处于惰性状态。本质上,这些标记就是隐藏的 DOM,它们不会被渲染。
- 处于模板中的内容不会有副作用。脚本不会运行,图片不会加载,音频不会播放,…直到模板被使用。
- 内容不在文档中。在主页面使用 getElementById() 或 querySelector() 不会返回模板的子节点。
- 模板能够被放置在任何位置,包括
<head>
、<body>
或 <frameset>
,并且任何能够出现在以上元素中的内容都可以放到模板中。 注意,”任何位置”意味着 <template>
能够安全的出现在 HTML 解析器不允许出现的位置…几乎可以作为任何内容模型的子节点。
每一个 <template>
元素都有一个关联的 DocumentFragment
对象(即模版内容)。
激活模版
要使用模板,你得先激活它。否则它的内容将永远无法渲染。 激活模板最简单的方法就是使用 document.importNode()
对模板的 .content
属性进行深拷贝。 .content
为只读属性,关联一个包含模板内容的 DocumentFragment
。
1 2 3 4 5
| let t = document.querySelector('#my-template'); t.content.querySelector('img').src = 'xx/xx/xx.png'; let cloneTmpl = document.importNode(t.content, true); document.body.appendChild(cloneTmpl);
|
在对模板进行冲压(stamping out)后,它的内容开始”启用”。 在本例中,内容被拷贝,发出图片请求,最终的标记得以渲染。
示例
模版的惰性
该示例示范了模板内容的惰性。<script>
只有在按钮被按下,模板被激活后才会运行。
1 2 3 4 5 6 7
| <button id="useTmpl">使用模版</button> <div id="container-1"></div> <template id="tmpl-1"> <div>第<span>0</span>次使用模版</div> <script>alert(100);</script> </template>
|
1 2 3 4 5 6
| document.querySelector('#useTmpl').addEventListener('click', function (e) { let content = document.querySelector('#tmpl-1').content; var span = content.querySelector('span'); span.textContent = parseInt(span.textContent) + 1; document.querySelector('#container-1').appendChild(document.importNode(content, true)); });
|
第0次使用模版
从模板中生成 Shadow DOM
很多时候我们会使用 innerHTML
属性为某个元素设置内容,例如在Shadow DOM中;该做法的弊端在于,你的 Shadow DOM 越复杂,就需要越多的字符串拼接操作。这不利于扩展,且该做法最容易滋生 XSS!这时我们就可以使用 <template>
来避免上述问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <div id="container-2"><p>这里是说明</p></div> <template id="tmpl-2"> <style type="text/css"> :host { border: 2px dashed green !important; padding: 4px !important } </style> <div> <h3>添加评论</h3> <content select="p"></content> <textarea></textarea> <footer><button>发表</button></footer> </div> </template>
|
1 2
| let sr = document.querySelector('#container-2').createShadowRoot(); sr.appendChild(document.querySelector('#tmpl-2').content);
|
添加评论