<template>标签元素
template元素用于声明HTML片段,该HTML片段可以通过脚本(script)被克隆以及插入到文档中。
而在浏览器的渲染过程中,template元素内的内容是不会被渲染的。
template.content:
返回template标签内的内容,该内容存储在与另外一个Document关联的文档片段中(Document Fragment),这样就避免了template的内容影响到主文档(Document)。(如,避免了表单控件被提交,脚本被执行,等等)
特性检测:
function supportsTemplate() { return 'content' in document.createElement('template'); }
<template> 会在标签中定义一个模板。它包含了“模板内容”,这些内容为可克隆的惰性DOM块。可以把模板看成在整个开发过程中可以使用(重用)的脚手架的组成部分。
创建一个模板内容:
<template id="mytemplate">
<img src="" alt="photo"/>
<div class="comment"></div>
</template>
包裹在<template>中的内容具有几个重要特性:
1、它的内容在被激活前一直处于惰性状态。这些标签是隐藏的DOM且不会被渲染。
2、模板中的内容不会带来副作用,脚本不会执行,图片不会加载,音频不会播放,...直到模板被使用。
3、模板内容被当做在文档之外的东西。在主页面中使用document.getElementById()或querySelector()不会返回模板的子节点;
4、模板可以放在<head>,<body>或<frameset>内的任何地方,而且上述标签中能够出现的任何内容都可以放在模板中。“任何地方”意味着<template>能够安全地出现在几乎所有HTML解析器不允许出现的位置除了内容模型的子节点。它也可以作为<table>或<select>元素的子节点。
<table>
<tr>
<template id="cells-to-repeat">
<td>some content</td>
</template>
</tr>
</table>
要使用一个模板,首先得激活它,否则它的内容将永远无法渲染。激活模板最简单的方法就是使用document.importNode()对模板的.content进行深拷贝。.content是DocumentFragment的一个只读属性,它包含了模板的内容。
var t = document.querySelector('#mytemplate'); t.content.querySelector('img').src = 'logo.png'; var clone = document.importNode(t.content, true); document.body.appendChild(clone);
Demos:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Demos</title>
</head>
<body>
<button οnclick="useIt()">Use me</button>
<div id="container"></div>
<script>
function useIt() {
var content = document.querySelector('template').content;
var span = content.querySelector('span');
span.textContent = parseInt(span.textContent) + 1;
document.querySelector('#container').appendChild(
document.importNode(content, true)
);
}
</script>
<template>
<div>
Template used: <span>0</span>
</div>
<script>
alert('Thanks!');
</script>
</template>
</body>
</html>
只有【Use me】按钮被点击后,模板中的脚本才会被执行。而在此之前脚本是不会执行的。
虽然可以通过对.innerHTML赋值为一串标签来将Shadow DOM挂再到Shadow Host上,如:
<div id="host"></div>
<script>
var shadow = document.querySelector('#host').createShadowRoot();
shadow.innerHTML = '<span>Host node</span>';
</script>
但这种方法不利于扩展与维护,如果Shadow DOM结构越复杂,就需要越多的字符串拼接操作,而且容易导致XSS问题。
而使用<template>能合理地解决:将模板内容附加到Shadow root上,如:
<template>
<style>
:host {
background: #f8f8f8;
padding: 10px;
transition: all 400ms ease-in-out;
box-sizing: border-box;
border-radius: 5px;
width: 450px;
max-width: 100%;
}
:host:hover {
background: #ccc;
}
div {
position: relative;
}
header {
padding: 5px;
border-bottom: 1px solid #aaa;
}
h3 {
margin: 0 !important;
}
textarea {
font-family: inherit;
width: 100%;
height: 100px;
box-sizing: border-box;
border: 1px solid #aaa;
}
footer {
position: absolute;
bottom: 10px;
right: 5px;
}
</style>
<div>
<header>
<h3>Add a Comment</h3>
</header>
<content select="p"></content>
<textarea></textarea>
<footer>
<button>Post</button>
</footer>
</div>
</template>
<div id="host">
<p>Instructions go here</p>
</div>
<script>
var shadow = document.querySelector('#host').createShadowRoot();
shadow.appendChild(document.querySelector('template').content);
</script>