?
This document uses PHP Chinese website manual Release
概述
template標(biāo)簽
基本用法
document.importNode()
Custom Element
document.registerElement()
添加屬性和方法
回調(diào)函數(shù)
Shadow DOM
HTML Import
基本操作
腳本的執(zhí)行
Web Component的封裝
Polymer.js
直接使用的組件
安裝
自定義組件
組件的使用方法
參考鏈接
各種網(wǎng)站往往需要一些相同的模塊,比如日歷、調(diào)色板等等,這種模塊就被稱為“組件”(component)。Web Component就是網(wǎng)頁(yè)組件式開發(fā)的技術(shù)規(guī)范。
采用組件進(jìn)行網(wǎng)站開發(fā),有很多優(yōu)點(diǎn)。
(1)管理和使用非常容易。加載或卸載組件,只要添加或刪除一行代碼就可以了。
<link rel="import" href="my-dialog.htm"> <my-dialog heading="A Dialog">Lorem ipsum</my-dialog>
上面代碼加載了一個(gè)對(duì)話框組件。
(2)定制非常容易。組件往往留出接口,供使用者設(shè)置常見屬性,比如上面代碼的heading屬性,就是用來(lái)設(shè)置對(duì)話框的標(biāo)題。
(3)組件是模塊化編程思想的體現(xiàn),非常有利于代碼的重用。標(biāo)準(zhǔn)格式的模塊,可以跨平臺(tái)、跨框架使用,構(gòu)建、部署和與其他UI元素互動(dòng)都有統(tǒng)一做法。
(4)組件提供了HTML、CSS、JavaScript封裝的方法,實(shí)現(xiàn)了與同一頁(yè)面上其他代碼的隔離。
未來(lái)的網(wǎng)站開發(fā),可以像搭積木一樣,把組件合在一起,就組成了一個(gè)網(wǎng)站。這是非常誘人的。
Web Components不是單一的規(guī)范,而是一系列的技術(shù)組成,包括Template、Custom Element、Shadow DOM、HTML Import四種技術(shù)規(guī)范。使用時(shí),并不一定這四者都要用到。其中,Custom Element和Shadow DOM最重要,Template和HTML Import只起到輔助作用。
template標(biāo)簽表示網(wǎng)頁(yè)中某些重復(fù)出現(xiàn)的部分的代碼模板。它存在于DOM之中,但是在頁(yè)面中不可見。
下面的代碼用來(lái)檢查,瀏覽器是否支持template標(biāo)簽。
function supportsTemplate() { return 'content' in document.createElement('template'); } if (supportsTemplate()) { // 支持 } else { // 不支持 }
下面是一個(gè)模板的例子。
<template id="profileTemplate"> <div class="profile"> <img src="" class="profile__img"> <div class="profile__name"></div> <div class="profile__social"></div> </div> </template>
使用的時(shí)候,需要用JavaScript在模板中插入內(nèi)容,然后將其插入DOM。
var template = document.querySelector('#profileTemplate'); template.querySelector('.profile__img').src = 'profile.jpg'; template.querySelector('.profile__name').textContent = 'Barack Obama'; template.querySelector('.profile__social').textContent = 'Follow me on Twitter'; document.body.appendChild(template.content);
上面的代碼是將模板直接插入DOM,更好的做法是克隆template節(jié)點(diǎn),然后將克隆的節(jié)點(diǎn)插入DOM。這樣做可以多次使用模板。
var clone = document.importNode(template.content, true); document.body.appendChild(clone);
接受template插入的元素,叫做宿主元素(host)。在template之中,可以對(duì)宿主元素設(shè)置樣式。
<template> <style> :host { background: #f8f8f8; } :host(:hover) { background: #ccc; } </style> </template>
document.importNode方法用于克隆外部文檔的DOM節(jié)點(diǎn)。
var iframe = document.getElementsByTagName("iframe")[0]; var oldNode = iframe.contentWindow.document.getElementById("myNode"); var newNode = document.importNode(oldNode, true); document.getElementById("container").appendChild(newNode);
上面例子是將iframe窗口之中的節(jié)點(diǎn)oldNode,克隆進(jìn)入當(dāng)前文檔。
注意,克隆節(jié)點(diǎn)之后,還必須用appendChild方法將其加入當(dāng)前文檔,否則不會(huì)顯示。換個(gè)角度說(shuō),這意味著插入外部文檔節(jié)點(diǎn)之前,必須用document.importNode方法先將這個(gè)節(jié)點(diǎn)準(zhǔn)備好。
document.importNode方法接受兩個(gè)參數(shù),第一個(gè)參數(shù)是外部文檔的DOM節(jié)點(diǎn),第二個(gè)參數(shù)是一個(gè)布爾值,表示是否連同子節(jié)點(diǎn)一起克隆,默認(rèn)為false。大多數(shù)情況下,必須顯式地將第二個(gè)參數(shù)設(shè)為true。
HTML預(yù)定義的網(wǎng)頁(yè)元素,有時(shí)并不符合我們的需要,這時(shí)可以自定義網(wǎng)頁(yè)元素,這就叫做Custom Element。它是Web component技術(shù)的核心。舉例來(lái)說(shuō),你可以自定義一個(gè)叫做super-button的網(wǎng)頁(yè)元素。
<super-button></super-button>
注意,自定義網(wǎng)頁(yè)元素的標(biāo)簽名必須含有連字符(-),一個(gè)或多個(gè)都可。這是因?yàn)闉g覽器內(nèi)置的的HTML元素標(biāo)簽名,都不含有連字符,這樣可以做到有效區(qū)分。
下面的代碼用于測(cè)試瀏覽器是否支持自定義元素。
if ('registerElement' in document) { // 支持 } else { // 不支持 }
使用自定義元素前,必須用document對(duì)象的registerElement方法登記該元素。該方法返回一個(gè)自定義元素的構(gòu)造函數(shù)。
var SuperButton = document.registerElement('super-button'); document.body.appendChild(new SuperButton());
上面代碼生成自定義網(wǎng)頁(yè)元素的構(gòu)造函數(shù),然后通過(guò)構(gòu)造函數(shù)生成一個(gè)實(shí)例,將其插入網(wǎng)頁(yè)。
可以看到,document.registerElement方法的第一個(gè)參數(shù)是一個(gè)字符串,表示自定義的網(wǎng)頁(yè)元素標(biāo)簽名。該方法還可以接受第二個(gè)參數(shù),表示自定義網(wǎng)頁(yè)元素的原型對(duì)象。
var MyElement = document.registerElement('user-profile', { prototype: Object.create(HTMLElement.prototype) });
上面代碼注冊(cè)了自定義元素user-profile。第二個(gè)參數(shù)指定該元素的原型為HTMLElement.prototype(瀏覽器內(nèi)部所有Element節(jié)點(diǎn)的原型)。
但是,如果寫成上面這樣,自定義網(wǎng)頁(yè)元素就跟普通元素沒有太大區(qū)別。自定義元素的真正優(yōu)勢(shì)在于,可以自定義它的API。
var buttonProto = Object.create(HTMLElement.prototype); buttonProto.print = function() { console.log('Super Button!'); } var SuperButton = document.registerElement('super-button', { prototype: buttonProto }); var supperButton = document.querySelector('super-button'); supperButton.print();
上面代碼在原型對(duì)象上定義了一個(gè)print方法,然后將其指定為super-button元素的原型。因此,所有supper-button實(shí)例都可以調(diào)用print這個(gè)方法。
如果想讓自定義元素繼承某種特定的網(wǎng)頁(yè)元素,就要指定extends屬性。比如,想讓自定義元素繼承h1元素,需要寫成下面這樣。
var MyElement = document.registerElement('another-heading', { prototype: Object.create(HTMLElement.prototype), extends: 'h1' });
另一個(gè)是自定義按鈕(button)元素的例子。
var MyButton = document.registerElement('super-button', { prototype: Object.create(HTMLButtonElement.prototype), extends: 'button' });
如果要繼承一個(gè)自定義元素(比如x-foo-extended
繼承x-foo
),也是采用extends屬性。
var XFooExtended = document.registerElement('x-foo-extended', { prototype: Object.create(HTMLElement.prototype), extends: 'x-foo' });
定義了自定義元素以后,使用的時(shí)候,有兩種方法。一種是直接使用,另一種是間接使用,指定為某個(gè)現(xiàn)有元素是自定義元素的實(shí)例。
<!-- 直接使用 --> <supper-button></supper-button> <!-- 間接使用 --> <button is="supper-button"></button>
總之,如果A元素繼承了B元素。那么,B元素的is屬性,可以指定B元素是A元素的一個(gè)實(shí)例。
自定義元素的強(qiáng)大之處,就是可以在它上面定義新的屬性和方法。
var XFooProto = Object.create(HTMLElement.prototype); var XFoo = document.registerElement('x-foo', {prototype: XFooProto});
上面代碼注冊(cè)了一個(gè)x-foo標(biāo)簽,并且指明原型繼承HTMLElement.prototype?,F(xiàn)在,我們就可以在原型上面,添加新的屬性和方法。
// 添加屬性 Object.defineProperty(XFooProto, "bar", {value: 5}); // 添加方法 XFooProto.foo = function() { console.log('foo() called'); }; // 另一種寫法 var XFoo = document.registerElement('x-foo', { prototype: Object.create(HTMLElement.prototype, { bar: { get: function() { return 5; } }, foo: { value: function() { console.log('foo() called'); } } }) });
自定義元素的原型有一些屬性,用來(lái)指定回調(diào)函數(shù),在特定事件發(fā)生時(shí)觸發(fā)。
createdCallback:實(shí)例生成時(shí)觸發(fā)
attachedCallback:實(shí)例插入HTML文檔時(shí)觸發(fā)
detachedCallback:實(shí)例從HTML文檔移除時(shí)觸發(fā)
attributeChangedCallback(attrName, oldVal, newVal):實(shí)例的屬性發(fā)生改變時(shí)(添加、移除、更新)觸發(fā)
下面是一個(gè)例子。
var proto = Object.create(HTMLElement.prototype); proto.createdCallback = function() { console.log('created'); this.innerHTML = 'This is a my-demo element!'; }; proto.attachedCallback = function() { console.log('attached'); }; var XFoo = document.registerElement('x-foo', {prototype: proto});
利用回調(diào)函數(shù),可以方便地在自定義元素中插入HTML語(yǔ)句。
var XFooProto = Object.create(HTMLElement.prototype); XFooProto.createdCallback = function() { this.innerHTML = "<b>I'm an x-foo-with-markup!</b>"; }; var XFoo = document.registerElement('x-foo-with-markup', {prototype: XFooProto});
上面代碼定義了createdCallback回調(diào)函數(shù),生成實(shí)例時(shí),該函數(shù)運(yùn)行,插入如下的HTML語(yǔ)句。
<x-foo-with-markup> <b>I'm an x-foo-with-markup!</b> </x-foo-with-markup>
所謂Shadow DOM指的是,瀏覽器將模板、樣式表、屬性、JavaScript代碼等,封裝成一個(gè)獨(dú)立的DOM元素。外部的設(shè)置無(wú)法影響到其內(nèi)部,而內(nèi)部的設(shè)置也不會(huì)影響到外部,與瀏覽器處理原生網(wǎng)頁(yè)元素(比如元素)的方式很像。Shadow DOM最大的好處有兩個(gè),一是可以向用戶隱藏細(xì)節(jié),直接提供組件,二是可以封裝內(nèi)部樣式表,不會(huì)影響到外部。Chrome 35+支持Shadow DOM。
Shadow DOM元素必須依存在一個(gè)現(xiàn)有的DOM元素之下,通過(guò)createShadowRoot方法創(chuàng)造,然后將其插入該元素。
var shadowRoot = element.createShadowRoot(); shadowRoot.appendChild(document.body);
上面代碼創(chuàng)造了一個(gè)shadowRoot元素,然后將其插入HTML文檔。
下面的例子是指定網(wǎng)頁(yè)中某個(gè)現(xiàn)存的元素,作為Shadom DOM的根元素。
<button>Hello, world!</button> <script> var host = document.querySelector('button'); var root = host.createShadowRoot(); root.textContent = '你好'; </script>
上面代碼指定現(xiàn)存的button元素,為Shadow DOM的根元素,并將button的文字從英文改為中文。
通過(guò)innerHTML屬性,可以為Shadow DOM指定內(nèi)容。
var shadow = document.querySelector('#hostElement').createShadowRoot(); shadow.innerHTML = '<p>Here is some new text</p>'; shadow.innerHTML += '<style>p { color: red };</style>';
下面的例子是為Shadow DOM加上獨(dú)立的模板。
<div id="nameTag">張三</div> <template id="nameTagTemplate"> <style> .outer { border: 2px solid brown; } </style> <div class="outer"> <div class="boilerplate"> Hi! My name is </div> <div class="name"> Bob </div> </div> </template>
上面代碼是一個(gè)div元素和模板。接下來(lái),就是要把模板應(yīng)用到div元素上。
var shadow = document.querySelector('#nameTag').createShadowRoot(); var template = document.querySelector('#nameTagTemplate'); shadow.appendChild(template.content.cloneNode());
上面代碼先用createShadowRoot方法,對(duì)div創(chuàng)造一個(gè)根元素,用來(lái)指定Shadow DOM,然后把模板元素添加為Shadow的子元素。
長(zhǎng)久以來(lái),網(wǎng)頁(yè)可以加載外部的樣式表、腳本、圖片、多媒體,卻無(wú)法方便地加載其他網(wǎng)頁(yè),iframe和ajax都只能提供部分的解決方案,且有很大的局限。HTML Import就是為了解決加載外部網(wǎng)頁(yè)這個(gè)問(wèn)題,而提出來(lái)的。
下面代碼用于測(cè)試當(dāng)前瀏覽器是否支持HTML Import。
function supportsImports() { return 'import' in document.createElement('link'); } if (supportsImports()) { // 支持 } else { // 不支持 }
HTML Import用于將外部的HTML文檔加載進(jìn)當(dāng)前文檔。我們可以將組件的HTML、CSS、JavaScript封裝在一個(gè)文件里,然后使用下面的代碼插入需要使用該組件的網(wǎng)頁(yè)。
<link rel="import" href="dialog.html">
上面代碼在網(wǎng)頁(yè)中插入一個(gè)對(duì)話框組件,該組建封裝在dialog.html
文件。注意,dialog.html文件中的樣式和JavaScript腳本,都對(duì)所插入的整個(gè)網(wǎng)頁(yè)有效。
假定A網(wǎng)頁(yè)通過(guò)HTML Import加載了B網(wǎng)頁(yè),即B是一個(gè)組件,那么B網(wǎng)頁(yè)的樣式表和腳本,對(duì)A網(wǎng)頁(yè)也有效(準(zhǔn)確得說(shuō),只有style標(biāo)簽中的樣式對(duì)A網(wǎng)頁(yè)有效,link標(biāo)簽加載的樣式表對(duì)A網(wǎng)頁(yè)無(wú)效)。所以可以把多個(gè)樣式表和腳本,都放在B網(wǎng)頁(yè)中,都從那里加載。這對(duì)大型的框架,是很方便的加載方法。
如果B與A不在同一個(gè)域,那么A所在的域必須打開CORS。
<!-- example.com必須打開CORS --> <link rel="import" href="http://example.com/elements.html">
除了用link標(biāo)簽,也可以用JavaScript調(diào)用link元素,完成HTML Import。
var link = document.createElement('link'); link.rel = 'import'; link.href = 'file.html' link.onload = function(e) {...}; link.onerror = function(e) {...}; document.head.appendChild(link);
HTML Import加載成功時(shí),會(huì)在link元素上觸發(fā)load事件,加載失敗時(shí)(比如404錯(cuò)誤)會(huì)觸發(fā)error事件,可以對(duì)這兩個(gè)事件指定回調(diào)函數(shù)。
<script async> function handleLoad(e) { console.log('Loaded import: ' + e.target.href); } function handleError(e) { console.log('Error loading import: ' + e.target.href); } </script> <link rel="import" href="file.html" onload="handleLoad(event)" onerror="handleError(event)">
上面代碼中,handleLoad和handleError函數(shù)的定義,必須在link元素的前面。因?yàn)闉g覽器元素遇到link元素時(shí),立刻解析并加載外部網(wǎng)頁(yè)(同步操作),如果這時(shí)沒有對(duì)這兩個(gè)函數(shù)定義,就會(huì)報(bào)錯(cuò)。
HTML Import是同步加載,會(huì)阻塞當(dāng)前網(wǎng)頁(yè)的渲染,這主要是為了樣式表的考慮,因?yàn)橥獠烤W(wǎng)頁(yè)的樣式表對(duì)當(dāng)前網(wǎng)頁(yè)也有效。如果想避免這一點(diǎn),可以為link元素加上async屬性。當(dāng)然,這也意味著,如果外部網(wǎng)頁(yè)定義了組件,就不能立即使用了,必須等HTML Import完成,才能使用。
<link rel="import" href="/path/to/import_that_takes_5secs.html" async>
但是,HTML Import不會(huì)阻塞當(dāng)前網(wǎng)頁(yè)的解析和腳本執(zhí)行(即阻塞渲染)。這意味著在加載的同時(shí),主頁(yè)面的腳本會(huì)繼續(xù)執(zhí)行。
最后,HTML Import支持多重加載,即被加載的網(wǎng)頁(yè)同時(shí)又加載其他網(wǎng)頁(yè)。如果這些網(wǎng)頁(yè)都重復(fù)加載同一個(gè)外部腳本,瀏覽器只會(huì)抓取并執(zhí)行一次該腳本。比如,A網(wǎng)頁(yè)加載了B網(wǎng)頁(yè),它們各自都需要加載jQuery,瀏覽器只會(huì)加載一次jQuery。
外部網(wǎng)頁(yè)的內(nèi)容,并不會(huì)自動(dòng)顯示在當(dāng)前網(wǎng)頁(yè)中,它只是儲(chǔ)存在瀏覽器中,等到被調(diào)用的時(shí)候才加載進(jìn)入當(dāng)前網(wǎng)頁(yè)。為了加載網(wǎng)頁(yè)網(wǎng)頁(yè),必須用DOM操作獲取加載的內(nèi)容。具體來(lái)說(shuō),就是使用link元素的import屬性,來(lái)獲取加載的內(nèi)容。這一點(diǎn)與iframe完全不同。
var content = document.querySelector('link[rel="import"]').import;
發(fā)生以下情況時(shí),link.import屬性為null。
瀏覽器不支持HTML Import
link元素沒有聲明
rel="import"
link元素沒有被加入DOM
link元素已經(jīng)從DOM中移除
對(duì)方域名沒有打開CORS
下面代碼用于從加載的外部網(wǎng)頁(yè)選取id為template的元素,然后將其克隆后加入當(dāng)前網(wǎng)頁(yè)的DOM。
var el = linkElement.import.querySelector('#template');document.body.appendChild(el.cloneNode(true));
當(dāng)前網(wǎng)頁(yè)可以獲取外部網(wǎng)頁(yè),反過(guò)來(lái)也一樣,外部網(wǎng)頁(yè)中的腳本,不僅可以獲取本身的DOM,還可以獲取link元素所在的當(dāng)前網(wǎng)頁(yè)的DOM。
// 以下代碼位于被加載(import)的外部網(wǎng)頁(yè) // importDoc指向被加載的DOM var importDoc = document.currentScript.ownerDocument; // mainDoc指向主文檔的DOM var mainDoc = document; // 將子頁(yè)面的樣式表添加主文檔 var styles = importDoc.querySelector('link[rel="stylesheet"]'); mainDoc.head.appendChild(styles.cloneNode(true));
上面代碼將所加載的外部網(wǎng)頁(yè)的樣式表,添加進(jìn)當(dāng)前網(wǎng)頁(yè)。
被加載的外部網(wǎng)頁(yè)的腳本是直接在當(dāng)前網(wǎng)頁(yè)的上下文執(zhí)行,因?yàn)樗?!-- /react-text -->window.document
指的是當(dāng)前網(wǎng)頁(yè)的document,而且它定義的函數(shù)可以被當(dāng)前網(wǎng)頁(yè)的腳本直接引用。
對(duì)于Web Component來(lái)說(shuō),HTML Import的一個(gè)重要應(yīng)用是在所加載的網(wǎng)頁(yè)中,自動(dòng)登記Custom Element。
<script> // 定義并登記<say-hi> var proto = Object.create(HTMLElement.prototype); proto.createdCallback = function() { this.innerHTML = 'Hello, <b>' + (this.getAttribute('name') || '?') + '</b>'; }; document.registerElement('say-hi', {prototype: proto}); </script> <template id="t"> <style> ::content > * { color: red; } </style> <span>I'm a shadow-element using Shadow DOM!</span> <content></content> </template> <script> (function() { var importDoc = document.currentScript.ownerDocument; //指向被加載的網(wǎng)頁(yè) // 定義并登記<shadow-element> var proto2 = Object.create(HTMLElement.prototype); proto2.createdCallback = function() { var template = importDoc.querySelector('#t'); var clone = document.importNode(template.content, true); var root = this.createShadowRoot(); root.appendChild(clone); }; document.registerElement('shadow-element', {prototype: proto2}); })(); </script>
上面代碼定義并登記了兩個(gè)元素:和。在主頁(yè)面使用這兩個(gè)元素,非常簡(jiǎn)單。
<head> <link rel="import" href="elements.html"> </head> <body> <say-hi name="Eric"></say-hi> <shadow-element> <div>( I'm in the light dom )</div> </shadow-element> </body>
不難想到,這意味著HTML Import使得Web Component變得可分享了,其他人只要拷貝elements.html
,就可以在自己的頁(yè)面中使用了。
Web Components是非常新的技術(shù),為了讓老式瀏覽器也能使用,Google推出了一個(gè)函數(shù)庫(kù)Polymer.js。這個(gè)庫(kù)不僅可以幫助開發(fā)者,定義自己的網(wǎng)頁(yè)元素,還提供許多預(yù)先制作好的組件,可以直接使用。
Polymer.js提供的組件,可以直接插入網(wǎng)頁(yè),比如下面的google-map。。
<script src="components/platform/platform.js"></script> <link rel="import" href="google-map.html"> <google-map lat="37.790" long="-122.390"></google-map>
再比如,在網(wǎng)頁(yè)中插入一個(gè)時(shí)鐘,可以直接使用下面的標(biāo)簽。
<polymer-ui-clock></polymer-ui-clock>
自定義標(biāo)簽與其他標(biāo)簽的用法完全相同,也可以使用CSS指定它的樣式。
polymer-ui-clock { width: 320px; height: 320px; display: inline-block; background: url("../assets/glass.png") no-repeat; background-size: cover; border: 4px solid rgba(32, 32, 32, 0.3); }
如果使用bower安裝,至少需要安裝platform和core components這兩個(gè)核心部分。
bower install --save Polymer/platform bower install --save Polymer/polymer
你還可以安裝所有預(yù)先定義的界面組件。
bower install Polymer/core-elements bower install Polymer/polymer-ui-elements
還可以只安裝單個(gè)組件。
bower install Polymer/polymer-ui-accordion
這時(shí),組件根目錄下的bower.json,會(huì)指明該組件的依賴的模塊,這些模塊會(huì)被自動(dòng)安裝。
{ "name": "polymer-ui-accordion", "private": true, "dependencies": { "polymer": "Polymer/polymer#0.2.0", "polymer-selector": "Polymer/polymer-selector#0.2.0", "polymer-ui-collapsible": "Polymer/polymer-ui-collapsible#0.2.0" }, "version": "0.2.0" }
下面是一個(gè)最簡(jiǎn)單的自定義組件的例子。
<link rel="import" href="../bower_components/polymer/polymer.html"> <polymer-element name="lorem-element"> <template> <p>Lorem ipsum</p> </template> </polymer-element>
上面代碼定義了lorem-element組件。它分成三個(gè)部分。
(1)import命令
import命令表示載入核心模塊
(2)polymer-element標(biāo)簽
polymer-element標(biāo)簽定義了組件的名稱(注意,組件名稱中必須包含連字符)。它還可以使用extends屬性,表示組件基于某種網(wǎng)頁(yè)元素。
<polymer-element name="w3c-disclosure" extends="button">
(3)template標(biāo)簽
template標(biāo)簽定義了網(wǎng)頁(yè)元素的模板。
在調(diào)用組件的網(wǎng)頁(yè)中,首先加載polymer.js庫(kù)和組件文件。
<script src="components/platform/platform.js"></script> <link rel="import" href="w3c-disclosure.html">
然后,分成兩種情況。如果組件不基于任何現(xiàn)有的HTML網(wǎng)頁(yè)元素(即定義的時(shí)候沒有使用extends屬性),則可以直接使用組件。
<lorem-element></lorem-element>
這時(shí)網(wǎng)頁(yè)上就會(huì)顯示一行字“Lorem ipsum”。
如果組件是基于(extends)現(xiàn)有的網(wǎng)頁(yè)元素,則必須在該種元素上使用is屬性指定組件。
<button is="w3c-disclosure">Expand section 1</button>
Dominic Cooney, Shadow DOM 101
Eric Bidelman, HTML's New Template Tag
Rey Bango, Using Polymer to Create Web Components
Cédric Trévisan, Building an Accessible Disclosure Button – using Web Components](http://blog.paciellogroup.com/2014/06/accessible-disclosure-button-using-web-components/)
Eric Bidelman, Custom Elements: defining new elements in HTML
Eric Bidelman, HTML Imports
TJ VanToll, Why Web Components Are Ready For Production
Chris Bateman, A No-Nonsense Guide to Web Components, Part 1: The Specs