建立自訂的HTML元素
我們可以使用 document.registerElement() 建立自訂的HTML元素,這個函數返回的是一個建構函式,第一個參數是用來聲明自訂HTML元素的名稱,第二個參數是可選的,用來描述原型的對象,自訂功能的元素。
在下面的樣本中,簡單的建立了一個新的HTML元素<x-treehouse>,並且將它放入到頁面中:
var XTreehouseElement = document.registerElement('x-treehouse');
document.body.appendChild(new XTreehouseElement());
下面的HTML就會插入<body>元素內:
<x-treehouse></x-treehouse>
自訂元素的名稱必須使用連字號-,這樣瀏覽器就可以區分標準元素和自訂元素。這也意味著,你不會遇到一個新的HTML元素和你自己定義元素使用相同名稱的問題。
給自訂元素建立JavaScript API
可以給自訂元素建立一個JavaScript API,這樣自訂元素就具備一系列的方法和屬性。要做到這一點,首先需要建立一個JavaScript對象。可以通過使用Object.create()方法。將HTMLElement.prototype傳給這個方法,建立一個對象。這個對象和標準的HTML的方法和屬性相同。
var XTreehouseProto = Object.create(HTMLElement.prototype);
可以像下面這樣,在這個新對像上定義你的需要的方法:
XTreehouseProto.hello = function(){
alert('Hello!');
}
使用Object.defineProperty()方法給自訂元素定義一個屬性。這個方法的第一個參數是需要定義屬性的對象,第二個參數是需被定義或修改的屬性名稱,第三個參數是需被定義或修改的屬性的描述符。在這裡你可以設定一個預設值指定屬性是可寫還是可讀。
Object.defineProperty(XTreehouseProto, 'badges', {
value: 20,
writable : true
});
一旦給自完義元素定義好API,需要通過document.registerElement()來調用。使用自訂元素的名稱作為第一個參數,然後給對象設定為一個名為prototype的屬性。這個屬性的值應該設定您在前面建立好的原型對象。
var XTreehouseElement = document.registerElement('x-treehouse', {
prototype: XTreehouseProto
});
一旦註冊自訂元素,可以建立一個新元素,並將其添加到頁面中。
var xtreehouse = new XTreehouseElement();
document.body.appendChild(xtreehouse);
可以像其他的HTML元素一樣使用前面定義好的方法和屬性。
xtreehouse.hello();
var badges = xtreehouse.badges;
擴充現有的元素
正如建立的自訂元素,還可以使用registerElement()方法來擴充現有的HTML元素的功能。比如我們可以擴充<img>元素來建立一個帶變數的縮圖顯示。
像之前那樣先建立一個對象原型。不過這次,是從現有的HTML元素上來擴充項物件原型。在這個樣本中,擴充的是HTMLImageElement。
var ThumbImageProto = Object.create(HTMLImageElement.prototype);
接下來使用createCallback定義一個函數(回呼函數),在建立元素時就定義了映像的width和height。
ThumbImageProto.createdCallback = function() {
this.width = '100';
this.height = '100';
};
還可以自訂自己的屬性和方法:
ThumbImageProto.changeImage = function() {
this.src = 'new-image.jpg';
};
當你想擴充元素時,在document.registerElement()建立元素時,可以通過給對象添加extends屬性。這個屬性的屬性值就是你需要擴充的元素名稱。
var ThumbImage = document.registerElement('thumb-img', {
prototype: ThumbImageProto,
extends: 'img'
});
要使用自訂元素,可以給元素指定一個屬性來擴充元素。這個屬性的值是自訂的元素名稱,可以告訴瀏覽器<img>使用了自訂的API:thumb-img。
<img is="thumb-img">
自訂元素回調方法
建立和管理自訂元素時有很多回調方法可使用:
createdCallback: 元素建立後調用
attachedCallback: 元素附加到文檔後調用
detachedCallback: 從文檔中移除元素後調用
attributeChangedCallback(attrName, oldValue, newValue): 元素任一屬性變更後調用
指定這些回呼函數的原型對象,並傳遞給document.registerElement()。
var XTreehouseProto = Object.create(HTMLElement.prototype);
XTreehouseProto.createdCallback = function() {}
XTreehouseProto.attachedCallback = function() {}
XTreehouseProto.detachedCallback = function() {}
XTreehouseProto.attributeChangedCallback = function(attrName, oldValue, newValue) {}
var XTreehouse = document.registerElement('x-treehouse', { prototype: XTreehouseProto });
使用Shadow DOM建立自訂元素
自訂元素真正的威力就是如何和Shadow DOM一起使用。使得它很容易建立可重用的組件。
在接下來的內容中將看看如何使用Shadow DOM自定元素,來建立一個網上商店可展示的商品。這裡的想法是,Web開發人員可通過添加一行HTML標籤來輕鬆的建立產品。需要顯示的產口所有資訊都通過自訂的data-屬性來完成。
<x-product data-name="Product Name" data-img="image.png" data-url="http://example.com"></x-product>
首先基於HTMLElement.prototype建立一個新的原型對象。
// Create a new object based of the HTMLElement prototype
var XProductProto = Object.create(HTMLElement.prototype);
接下來,我們需要設定一個createdCallback函數。我們將要建立一個<img>和<a>元素,用來顯示產品。先把代碼展示一下,再詳細介紹:
// Set up the element.
XProductProto.createdCallback = function() {
// Create a Shadow Root
var shadow = this.createShadowRoot();
// Create an img element and set it's attributes.
var img = document.createElement('img');
img.alt = this.getAttribute('data-name');
img.src = this.getAttribute('data-img');
img.width = '150';
img.height = '150';
img.className = 'product-img';
// Add the image to the Shadow Root.
shadow.appendChild(img);
// Add an event listener to the image.
img.addEventListener('click', function(e) {
window.location = this.getAttribute('data-url');
});
// Create a link to the product.
var link = document.createElement('a');
link.innerText = this.getAttribute('data-name');
link.href = this.getAttribute('data-url');
link.className = 'product-name';
// Add the link to the Shadow Root.
shadow.appendChild(link);
};
首先建立一個新的Shadow DOM。如果你對Shadow DOM不熟悉,可以先閱讀之前的文章。然後建立一個<img>元素,並設定其alt、src、width和height屬性指定x-product元素的一些資訊。
註:回呼函數,this指的是自訂元素的標記。
接下來將<img>和<a>元素添加到Shadow root下面。並設定元素的屬性值從自訂元素的data-屬性擷取。
現在我們需要註冊自訂元素,並且將x-product元素傳給document.registerElement(),同時指定對象原型為XProductProto:
// Register the new element.
var XProduct = document.registerElement('x-product', {
prototype: XProductProto
});
為了讓項目展示更好,需要添加一些CSS代碼:
x-product {
display: inline-block;
float: left;
margin: 0.5em;
border-radius: 3px;
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
font-family: Helvetica, arial, sans-serif;
-webkit-font-smoothing: antialiased;
}
x-product::shadow .product-img {
cursor: pointer;
background: #FFF;
margin: 0.5em;
}
x-product::shadow .product-name {
display: block;
text-align: center;
text-decoration: none;
color: #08C;
border-top: 1px solid #EEE;
font-weight: bold;
padding: 0.75em 0;
}
為了顯示產品,我們需要將<x-product>元素添加到HTML模板中。使用data-name,data-img和data-url屬性指定產品相關資料。當頁面載入時,自訂元素就會通過createCallback來調用它們。
<x-product data-name="Ruby" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/ruby.png" data-url="http://example.com/1"></x-product>
<x-product data-name="JavaScript" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/javascript.png" data-url="http://example.com/2"></x-product>
<x-product data-name="Python" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/python.png" data-url="http://example.com/3"></x-product>
就是這樣,你現在已經使用Shadow DOM自訂了一個元素,顯示一系列的產品。
全部執行個體代碼
HTML
<x-product data-name="Ruby" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/ruby.png" data-url="http://example.com/1"></x-product><x-product data-name="JavaScript" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/javascript.png" data-url="http://example.com/2"></x-product><x-product data-name="Python" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/python.png" data-url="http://example.com/3"></x-product>
CSS
body { background: #F7F7F7;}x-product { display: inline-block; float: left; margin: 0.5em; border-radius: 3px; background: #FFF; box-shadow: 0 1px 3px rgba(0,0,0,0.25); font-family: Helvetica, arial, sans-serif; -webkit-font-smoothing: antialiased; } x-product::shadow .product-img { cursor: pointer; background: #FFF; margin: 0.5em;} x-product::shadow .product-name { display: block; text-align: center; text-decoration: none; color: #08C; border-top: 1px solid #EEE; font-weight: bold; padding: 0.75em 0; }
JS
// Create a new object based of the HTMLElement prototypevar XProductProto = Object.create(HTMLElement.prototype);// Set up the element.XProductProto.createdCallback = function() { // Create a Shadow Root var shadow = this.createShadowRoot(); // Create a standard img element and set it's attributes. var img = document.createElement('img'); img.alt = this.getAttribute('data-name'); img.src = this.getAttribute('data-img'); img.width = '150'; img.height = '150'; img.className = 'product-img'; // Add the image to the Shadow Root. shadow.appendChild(img); // Add an event listener to the image. img.addEventListener('click', function(e) { window.location = this.getAttribute('data-url'); }); // Create a link to the product. var link = document.createElement('a'); link.innerText = this.getAttribute('data-name'); link.href = this.getAttribute('data-url'); link.className = 'product-name'; // Add the link to the Shadow Root. shadow.appendChild(link);};// Register the new element.var XProduct = document.registerElement('x-product', { prototype: XProductProto});
瀏覽器支援自訂HTML元素
Chrome 33+和Opera支援自訂元素。然而有一個強大的polyfill可以讓其他的瀏覽器,比如說Polymer和X-tags。
可以使用registerElement()方法檢測document對象是否被瀏覽器支援:
if ('registerElement' in document) {
// Supported.
} else {
// Not supported.
}
總結
通過本文的學習,相信你已經瞭解到如何使用js建立自訂HTML元素,還看到了如何使用自訂元素和Shadow DOM知識構建Web組件。