Web Components之Custom Elements

白牙青森發表於2015-03-13

什麼是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結構和樣式進行封裝。

 

相關文章