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>