WebComponent——template
在web开发领域中,模板并不少见。从服务器端的模板语言,如Django
、jsp
等,应用十分广泛,存在了很长时间。又如前端,早期例如art(artTemplate)
,以及近年来,大多数的MV*框架涌现,绝大多数在展现层使用了同样的渲染机制:模板。
定义 模板,一个拥有预制格式的文档或者文件,可作为特定应用的出发点,这样就避免在每次使用格式的时候都重复创建。
从模板的定义中,我们可以发现,“避免在每次使用格式的时候重复创建”,从这句话来看,模板可以让我们避免重复的工作。那么,web平台有没有提供原生支持呢?
答案是,有,在 WhatWG HTML 模板规范中,它定义了一个新的<template>
元素, 用于描述一个标准的以DOM为基础的方案来实现客户端模板。该模板允许你定义一段可以被转为 HTML 的标记,在页面加载时不生效,但可以在后续进行动态实例化。
声明
跟普通的html标签一样,template
标签包含的内容,即是声明的模板内容。
<template>
<img src="" />
<p>content</p>
</template>
“模板内容”本质上,是 一大块的惰性可复制DOM。在这个例子中,标签内的元素并不会被渲染,图片资源也不会发出请求。模板可以理解为单个零件,在整个应用的生命周期中,你都可以使用、以及重用它。
特性
使用<template>
标签包裹我们的内容,可以为我们提供一下几个重要的特性。
它的内容在激活前都是惰性的。 template标签默认是隐藏的,它的内容也是不可见的,同时也不会被渲染。
处于模板中的内容不会产生副作用。 放在模板中的脚本、音频、视频、图片资源不会被加载,不会被播放,直到模板中的内容被使用。
内容不在文档中。 在主页面使用
document.getElementById()
,不会返回模板子节点。模板能够放置在任何位置。 你可以把
<template>
放置在<head>
、<body>
、<frameset>
, 并且任何能够出现在以上元素的内容,都可以放置在模板中。“任何位置” 意味着<template>
标签可以出现在HTML解析器不允许出现的位置 (必须是在<html>
标签内),几乎可以作为任何元素的子节点。 它也可以作为<table>
、<select>
的子节点。当然,如果写在声明type="text/javascript"
的<script>
标签中,绝对报错,原因我就不说了。(同时实测发现,如果<template>
标签放在<head>
、<body>
同级,放在<body>
前面,都会被解析到<head>
标签内,放在<body>
后,会被解析到<body>
内)。<table> <tr> <templete> <td>content</td> </templete> </tr> </table>
使用模板
想要使用模板,首先需要激活模板,否则它的内容将无法被渲染。模板对象包含了一个content
属性,该属性是只读属性,关联一个包含模板内容的DocumentFragment
, 我们可以使用document.importNode()
对模板的.content
进行深拷贝。
<template id="template1">
<img src="" />
<p>content</p>
</template>
var tmp = document.querySelector('#template1')
// 可以在获取模板的时候,对内容进行填充
tmp.content.querySelector('img').scr = 'logo.png'
var clone = document.importNode(tmp.content, true)
document.body.appendChild(clone)
模板中的资源,比如图片资源,只有被激活后,才会发出请求。
浏览器支持
想要检测浏览器是否支持该标签,需要创建一个template元素,并检查它是否拥有.content
属性。
function supportTemplate() {
return 'content' in document.createElement('template')
}
if (supportsTemplate()) {
// 浏览器支持 template 元素
} else {
// 浏览器不支持template元素
}
从目前来看,IE13+开始支持,低于此版本的IE均无法使用,如果有项目只需要考虑 webkit内核的浏览器,template标签还是可以一用。
如果浏览器不支持template标签,那么就会认为是一个普通的自定义元素,内部的标签会被作为一般的标签被渲染。
模板标准之路
HTML 模板标准化进程耗时十分长久。从过去到现在,出现了很多各种各样的方法去创建可重用的模板。
方法一:使用隐藏的DOM元素,将模板内容放在某个标签内,使用display:none
隐藏元素。
<div style="display:none">
<img src="" />
</div>
使用这种方式,有利有弊:
- √ 使用DOM,浏览器能够很好的处理DOM结构,我们可以方便的复制、使用DOM。
- √ 没有内容渲染,
display: none
阻止了内容渲染。 - × 非惰性, 图片资源依然会发出请求。
- x 难以设置样式和主题,需要为所有CSS增加规则。
方法二:使用textarea 标签,并使用display:none
隐藏元素。
<textarea style="display:none">
<img src="" />
</textarea>
这种方法是对方法一的一种改进,但也有新的利弊:
- √ 没有内容渲染,
display: none
阻止了内容渲染。 - √ 惰性,由于模板内容是字符串,图片资源不会发出请求。
- x 模板内容是字符串,需要进一步将其转为DOM。
方法三: 重载脚本。
<script type="text/x-handlebars-template">
<img src='' />
</script>
利弊:
- √ 没有内容渲染,script 标签默认
display:none
。 - √ 惰性,脚本类型不为
text/javascript
,浏览器不会认为是脚本,不会将其作为JS解析。 - x 安全问题,由于使用
innerHTML
获取内容,对用户提供的字符串进行运行时解析,很容易倒是 XSS漏洞。
总结
模板标准化,使得我们在做web开发整个过程更加健全,更容易维护。