什麼是Web Component?
Web Components 包含了多種不同的技術。你可以把Web Components當做是用一系列的Web技術建立的、可重用的使用者介面元件的統稱。Web Components使開發人員擁有擴充套件瀏覽器標籤的能力,可以自由的進行定製元件。但截至本文時間,Web Components依然是W3C工作組的一個草案,併為被正式納入標準,但這並不妨礙我們去學習它。
Web元件
何為Web元件?Web元件相對於Web開發者來說並不陌生,Web元件是一套封裝好的HTML,CSS,以及JavaScript,它最大的特點就是可複用。基本在每一個網站上我們都可以看到各式各樣的元件,例如下拉選單、按鈕、圖片滾播、日曆控制元件等。慢著,既然我們已經可以實現web元件的封裝,那Web Component這傢伙出現的意義是什麼呢?Web Component回答道:“你們的實現方式不夠優雅也不夠完美,還是看看我的吧”。
因為當我們使用各種程式設計技巧對元件進行封裝時,一個無法規避的事實是,元件的內部是可被訪問和影響的,例如我們對樣式表進行改動時經常會擔心影響到頁面元件的樣式。而通過Web Component封裝出來的元件,我們可以選擇讓元件的內部隱藏起來,也就是說,元件內部是與世隔絕的!
Web Component的組成
- Custom Elements
- HTML Templates
- Shadow Dom
- HTML Imports
總的來說,Web Components包含以上四種技術,本文著重談談Custom Element,這也是Web component中最核心的部分。
Custom Elements
自定義元素是一個可由建立者來自定義介面的物件。在建立時我們需要通過 document.registerElement() 來對自定義元素進行註冊。該方法會返回一個元素的構造器,通過該構造器我們就可以建立我們的自定義元素的例項了。
var MyButton= document.registerElement('my-button'); document.body.appendChild(new MyButton());
實際上 document.registerElement(tag-name, prototype) 包含兩個引數:
tag-name: 自定義元素的標籤名,這個標籤名必須包含連字元'-',這樣做的母的是用以區分自定義元素和HTML規範的元素
prototype: 這是一個可選的引數,用於描述該元素的原型,在該元素中你可以為自定義元素進行介面的定義
var MyElement = document.registerElement('my-element', { prototype: Object.create(HTMLElement.prototype, { createdCallback: { value: function() { this.innerHTML = "<p>I'm a Custom Element</p>"; } } }) }); document.body.appendChild(new MyElement())
在上面的例子中,我們通過Object.create()方法建立了一個繼承自HTMLElement的物件作為自定義物件的原型,並設定了元素預設的 innerHTML ,如果你對Object.create()方法的第二個引數不熟悉,你最好先去查閱一下。實際上它的上面的例子跟下面給出的寫法的效果是一樣的:
var MyElementProto = Object.create(HTMLElement.prototype) MyElementProto.createdCallback = function() { this.innerHTML = "<p>I'm a Custom Element</p>" } var MyElement = document.registerElement('my-element', { prototype: MyElementProto }) document.body.appendChild(new MyElement())
接著,在頁面上我們可以看到渲染出如下結構:
自定義元素的生命週期
在上面的例子中我們可以看到自定義元素的原型上有一個 createdCallback 屬性,它的值是一個回撥函式,在自定義元素被建立的時候被呼叫。實際上自定義元素在它的生命週期中可能會經歷以下幾種變化:
- 自定義元素在其註冊前被建立
- 自定義元素被註冊
- 自定義元素的例項在自定義元素註冊後被建立
- 自定義元素被插入到文件中
- 自定義元素從文件中移除
- 自定義元素的屬性被建立、移除、修改
在自定義元素經歷上面某些變化時,不同的回撥函式會被呼叫。這些回撥函式被儲存在一個名為生命週期回撥的鍵值對集合中。我們可實現的回撥函式總共有以下4種,其中 attributeChangedCallback 的回撥函式中我們可以通過其引數訪問到操作的屬性名、老的屬性值、新的屬性值。
DOM:
<div id="modify"> <label class="CEgreen"><input type="radio" name="CEclass" value="green">green box</label> <label class="CEred"><input type="radio" name="CEclass" value="red">red box</label> </div>
JS:
var MyElement = document.registerElement('my-element', { prototype: Object.create(HTMLElement.prototype, { createdCallback: { value: function() { this.innerHTML = "<span>I'm a Custom Element</span>" } }, attributeChangedCallback: { value: function(property, oldValue, newValue) { this.innerHTML = "attribute '" + property + "' is modified to " + newValue } } }) }) document.body.appendChild(new MyElement()) var temp = document.querySelector("#modify") var myElement = document.querySelector("my-element") temp.addEventListener('click', function(e){ console.log(e.target.value) myElement.className = e.target.value })
另外,給自定義元素新增樣式和普通元素是一樣的,這是上面例子中為自定義元素新增的樣式:
my-element {display: inline-block;margin-top: 20px;padding: 10px;font-size: 24px;}
這就是一個最基礎的自定義元素的實現了。如果我們希望自定義元素內部不受外部樣式的影響,我們需要使用Shadow Dom來對內部dom結構和樣式進行封裝。