在上一章节中主要介绍了Custom elements(自定义元素),Shadow DOM(影子DOM)的使用,我们发现其实只使用上述的两种方式,已经可以构建我们平时需要的组件,那么为什么还需要HTML templates(HTML模板)技术呢?
不知道大家还记不记得之前创建元素的方式:
const input = document.createElement('input');
input.setAttribute('type', 'text');
input.setAttribute('class', 'input-vlaue');
创建一个input就需要写这些js代码,很明显,如果当html文档结构太深或者节点过多时,写出太多的创建html 节点的代码,还是很头疼的。一方面代码量过多且层级结构不清晰,另一方面时css也是用此方式创建,如何使用伪类呢? 多少是方便的。所以便有了HTML templates(HTML模板)技术。
我们先来看下它的定义:
HTML内容模板(<template>)元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现,但随后可以(原文为 may be)在运行时使用JavaScript实例化。") 和
<slot>
元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
其实就是它可以让你在编写组件时,可以预先定义好模板,然后再在模板上发展出自己的组件。
示例:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./main.js"></script>
</head>
<body>
<template id="my-paragraph">
<style>
p {
color: white;
background-color: #909090;
padding: 5px;
border: 1px soli silver;
}
</style>
<p><slot name="my-text">默认文本</slot></p>
</template>
<my-paragraph>
<span slot="my-text">个性化文本</span>
</my-paragraph>
<my-paragraph>
<ul slot="my-text">
<li>列表条目1</li>
<li>列表条目2</li>
</ul>
</my-paragraph>
</body>
</html>
main.js
customElements.define('my-paragraph',
class extends HTMLElement {
constructor() {
super();
const template = document.getElementById('my-paragraph');
const templateContent = template.content;
this.attachShadow({mode: 'open'}).appendChild(
templateContent.cloneNode(true)
);
}
}
);
定义模板的的代码:
<template id="my-paragraph">
<style>
p {
color: white;
background-color: #909090;
padding: 5px;
border: 1px soli silver;
}
</style>
<p><slot name="my-text">默认文本</slot></p>
</template>
由于这里的html import已经不被各大浏览器支持了,所以这里的定义模板的模块只能写到使用的html文本里面,或者使用js创建,写入到main.js里面。如下的例子,将template独立到js文件中。
示例:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./main.js"></script>
</head>
<body>
<my-paragraph>
<span slot="my-text">个性化文本</span>
</my-paragraph>
<my-paragraph>
<ul slot="my-text">
<li>列表条目1</li>
<li>列表条目2</li>
</ul>
</my-paragraph>
</body>
</html>
main.js
const str = `
<style>
p {
color: white;
background-color: #909090;
padding: 5px;
border: 1px soli silver;
}
</style>
<p><slot name="my-text">默认文本</slot></p>
`;
customElements.define('my-paragraph',
class extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
//const template = document.getElementById('my-paragraph');
// const templateContent = template.content;
const template = document.createElement('template');
template.innerHTML = str;
const templateContent = template.content;
shadow.appendChild(
templateContent.cloneNode(true)
);
}
}
);
以上便是对Web Components的一个基本的认识和使用。由此可以看出Web Components在组件化开发方向的优势,可是在使用过程中也有一定劣势,以下便是目前自己不太喜欢的地方:
个人不太喜欢的地方
- 无法在组件内部使用公共的样式,例如引入了外部样式,即使在组件内部使用该样式对应的class name也不会起作用,例如下面的代码,虽然在 slot外部的p标签内加了class name,但是在组件外部也是无法使用.test{}来定制样式了,这样一来就无法使用很多开源的css类库了。
const str = `
<style>
p {
color: white;
background-color: #909090;
padding: 5px;
border: 1px soli silver;
}
</style>
<p class="test"><slot name="my-text">默认文本</slot></p>
`;
- 没了html import 语法,template就只能定义显示的html文件中,显然这不是我们想要的组件,我们希望的组件是简洁明了,使用简单,而这看起来组件和html还有了耦合。当然也可以把template写入到js中,但是如果template结构复杂,就会发现自负串过长,代码结构不美观,且html,css,js混合到了一起。
- 其他的,暂时想不起来了...
参考网址:
MSDN:https://developer.mozilla.org/zh-CN/docs/Web/Web_Components
W3C: https://www.w3.org/html/ig/zh/wiki/Web-Components#.E7.AE.80.E4.BB.8B
web componets 实例代码:https://github.com/mdn/web-components-examples
HTML5 Rocks: https://www.html5rocks.com/en/tutorials/webcomponents/customelements/#instantiating
阮一峰:https://javascript.ruanyifeng.com/htmlapi/webcomponents.html#toc12
知乎:https://zhuanlan.zhihu.com/p/64619005