Web Components 是什么?
Web Components是W3C定义的新标准,它给了前端开发者扩展浏览器标签的能力,可以自由的定制组件,更好的进行模块化开发,彻底解放了前端开发者的生产力。
Web Components 架构
Web Components在 W3C 规范中的发展有几个模块:
- 模板元素
- Html Import
- Shadow DOM
- 自定义元素
- 装饰器
目前前四个模块足以支撑 Web Component,装饰器还没有一个完整的规范。
template 模板元素
创建一个template的 html 标签,通过 javascript 获取节点的模板内容
<template id="test">
test template
</template>
<h1 id="message"></h1>
<script type="text/javascript">
var template = document.getElementById("test");
console.log(template.content);
</script>
模板默认不显示,需要激活模板,通过以下两种方法来激活节点
-
克隆节点
var templateContent = template.content; var activeNode = templateContent.cloneNode(true); document.body.appendChild(activeNode);
-
导入节点
var templateContent = template.content; var activeNode = document.importNode(templateContent,true); document.body.appendChild(activeNode);
Html Import
Html Import 可以将外部的 HTML 文档嵌入到当前文档中,提供很好的资源共享。
带有import属性的link 支持两个事件
-
onload:文件成功引入页面会触发
-
onerror: 文件加载失败会触发
<script type="text/javascript"> function importTest(message){ console.log(message); } </script>
Shadow DOM
在 Web Component 规范出来之前,关于 HTML、CSS、Javascript 构建 Web 应用程序的程序的争论一直不断。主要质疑有几种:
- 样式覆盖:文档的样式会影响Web Component
- 脚本替换:文档的Javascript会覆盖Web Component的部分代码
- 重复的 ID:文档出现重复 ID 会导致解析异常
Shadow DOM的引入就是为了解决封装机制作用域的问题。
浏览器通常情况下是看不到Shadow DOM节点的,Google 开发工具可以帮我审查这些元素,需要做如下设定:
创建Shadow DOM : 通过 createShadowRoot 函数对一个 DOM 元素(宿主元素)创建一个 Shadow DOM 子树
<div id="box"></div><!--容器-->
<template id="test">
<style>
:host h1{color:red};
</style>
<h1>Test</h1>
</template>
<script type="text/javascript">
var box = document.getElementById("box");
var shadowRoot = box.createShadowRoot();
var template = document.getElementById("test");
var templateContent = template.content;
var activeNode = document.importNode(templateContent,true);
shadowRoot.appendChild(activeNode);
</script>
自定义元素
开发一个自定义元素需要五个步骤:
-
创建对象:
var objectProto = Object.create(HTMLElement.prototype);
-
定义对象属性:
//定义单个属性 Object.defineProperty(objectProto,'title',{ writable : true, }) //定义单个多个 Object.defineProperties(objectProto,{ height: {writable : true}, width: {writable : true} })
-
定义生命周期方法:
//成功创建对象 objectProto.createdCallback = function(){ console.log('created'); } //对象插入DOM中 objectProto.attachedCallback = function(){ console.log('attached'); }
-
注册新元素
document.registerElement('test',{ prototype : objectProto });
输入24px 的 HelloWorld:
<my-name title="HelloWorld" fontsize="2"></my-name>
<script type="text/javascript">
var objectProto = Object.create(HTMLElement.prototype);
Object.defineProperties(objectProto,{
title: {writable : true},
fontsize: {writable : true}
})
objectProto.createdCallback = function(){
this.innerText = this.attributes.title.value;
this.style.fontSize = this.attributes.fontsize.value * 12 + 'px';
}
document.registerElement('my-name',{
prototype : objectProto
});
</script>
时钟应用
- test.html :通过import方式加载Clock Component
- clock-elemect.html:负责倒计时的实现
test.html
<link rel="import" href="clock-element.html"/>
<digital-clock></digital-clock>
clock-elemect.html
<template id="clockTemplete">
<style>
:host::shadow .clock{
display: inline-flex;
justify-content: space-around;
background:white;
font-size: 8rem;
box-shadow: 2px 2px 4px -1px grey;
border: 1px solid green;
font-family: sans-serif;
width: 100%;
}
:host::shadow .clock .hour,
:host::shadow .clock .minute,
:host::shadow .clock .second{
color: orange;
padding: 1.5rem;
text-shadow: 0px 2px black;
}
</style>
<div class="clock">
<div class="hour">HH:</div>
<div class="minute">MM:</div>
<div class="second">SS</div>
</div>
</template>
<script type="text/javascript">
(function(){
var selfDoucment = document.currentScript.ownerDocument;
var objectProto = Object.create(HTMLElement.prototype);
objectProto.createdCallback = function(){
var shadow = this.createShadowRoot();
var templateContent = selfDoucment.querySelector('#clockTemplete').content;
var templateNode = selfDoucment.importNode(templateContent,true);
shadow.appendChild(templateNode);
var hourElement = shadow.querySelector('.hour');
var minuteElement = shadow.querySelector('.minute');
var secondElement = shadow.querySelector('.second');
window.setInterval(function(){
var date = new Date();
hourElement.innerText = date.getHours()+':';
minuteElement.innerText = date.getMinutes()+':';
secondElement.innerText = date.getSeconds();
},1000);
};
document.registerElement('digital-clock',{
prototype : objectProto
});
})();
</script>