[TOC]
## 概述
各種網站往往需要一些相同的模塊,比如日歷、調色板等等,這種模塊就被稱為“組件”(component)。Web Component就是網頁組件式開發的技術規范。
采用組件進行網站開發,有很多優點。
(1)管理和使用非常容易。加載或卸載組件,只要添加或刪除一行代碼就可以了。
~~~
<link rel="import" href="my-dialog.htm">
<my-dialog heading="A Dialog">Lorem ipsum</my-dialog>
~~~
上面代碼加載了一個對話框組件。
(2)定制非常容易。組件往往留出接口,供使用者設置常見屬性,比如上面代碼的heading屬性,就是用來設置對話框的標題。
(3)組件是模塊化編程思想的體現,非常有利于代碼的重用。標準格式的模塊,可以跨平臺、跨框架使用,構建、部署和與其他UI元素互動都有統一做法。
(4)組件提供了HTML、CSS、JavaScript封裝的方法,實現了與同一頁面上其他代碼的隔離。
未來的網站開發,可以像搭積木一樣,把組件合在一起,就組成了一個網站。這是非常誘人的。
Web Components不是單一的規范,而是一系列的技術組成,包括Template、Custom Element、Shadow DOM、HTML Import四種技術規范。使用時,并不一定這四者都要用到。其中,Custom Element和Shadow DOM最重要,Template和HTML Import只起到輔助作用。
## template標簽
### 基本用法
template標簽表示網頁中某些重復出現的部分的代碼模板。它存在于DOM之中,但是在頁面中不可見。
下面的代碼用來檢查,瀏覽器是否支持template標簽。
~~~
function supportsTemplate() {
return 'content' in document.createElement('template');
}
if (supportsTemplate()) {
// 支持
} else {
// 不支持
}
~~~
下面是一個模板的例子。
~~~
<template id="profileTemplate">
<div class="profile">
<img src="" class="profile__img">
<div class="profile__name"></div>
<div class="profile__social"></div>
</div>
</template>
~~~
使用的時候,需要用JavaScript在模板中插入內容,然后將其插入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節點,然后將克隆的節點插入DOM。這樣做可以多次使用模板。
~~~
var clone = document.importNode(template.content, true);
document.body.appendChild(clone);
~~~
接受template插入的元素,叫做宿主元素(host)。在template之中,可以對宿主元素設置樣式。
~~~
<template>
<style>
:host {
background: #f8f8f8;
}
:host(:hover) {
background: #ccc;
}
</style>
</template>
~~~
### document.importNode()
document.importNode方法用于克隆外部文檔的DOM節點。
~~~
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窗口之中的節點oldNode,克隆進入當前文檔。
注意,克隆節點之后,還必須用appendChild方法將其加入當前文檔,否則不會顯示。換個角度說,這意味著插入外部文檔節點之前,必須用document.importNode方法先將這個節點準備好。
document.importNode方法接受兩個參數,第一個參數是外部文檔的DOM節點,第二個參數是一個布爾值,表示是否連同子節點一起克隆,默認為false。大多數情況下,必須顯式地將第二個參數設為true。
## Custom Element
HTML預定義的網頁元素,有時并不符合我們的需要,這時可以自定義網頁元素,這就叫做Custom Element。它是Web component技術的核心。舉例來說,你可以自定義一個叫做super-button的網頁元素。
~~~
<super-button></super-button>
~~~
注意,自定義網頁元素的標簽名必須含有連字符(-),一個或多個都可。這是因為瀏覽器內置的的HTML元素標簽名,都不含有連字符,這樣可以做到有效區分。
下面的代碼用于測試瀏覽器是否支持自定義元素。
~~~
if ('registerElement' in document) {
// 支持
} else {
// 不支持
}
~~~
### document.registerElement()
使用自定義元素前,必須用document對象的registerElement方法登記該元素。該方法返回一個自定義元素的構造函數。
~~~
var SuperButton = document.registerElement('super-button');
document.body.appendChild(new SuperButton());
~~~
上面代碼生成自定義網頁元素的構造函數,然后通過構造函數生成一個實例,將其插入網頁。
可以看到,document.registerElement方法的第一個參數是一個字符串,表示自定義的網頁元素標簽名。該方法還可以接受第二個參數,表示自定義網頁元素的原型對象。
~~~
var MyElement = document.registerElement('user-profile', {
prototype: Object.create(HTMLElement.prototype)
});
~~~
上面代碼注冊了自定義元素user-profile。第二個參數指定該元素的原型為HTMLElement.prototype(瀏覽器內部所有Element節點的原型)。
但是,如果寫成上面這樣,自定義網頁元素就跟普通元素沒有太大區別。自定義元素的真正優勢在于,可以自定義它的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();
~~~
上面代碼在原型對象上定義了一個print方法,然后將其指定為super-button元素的原型。因此,所有supper-button實例都可以調用print這個方法。
如果想讓自定義元素繼承某種特定的網頁元素,就要指定extends屬性。比如,想讓自定義元素繼承h1元素,需要寫成下面這樣。
~~~
var MyElement = document.registerElement('another-heading', {
prototype: Object.create(HTMLElement.prototype),
extends: 'h1'
});
~~~
另一個是自定義按鈕(button)元素的例子。
~~~
var MyButton = document.registerElement('super-button', {
prototype: Object.create(HTMLButtonElement.prototype),
extends: 'button'
});
~~~
如果要繼承一個自定義元素(比如`x-foo-extended`繼承`x-foo`),也是采用extends屬性。
~~~
var XFooExtended = document.registerElement('x-foo-extended', {
prototype: Object.create(HTMLElement.prototype),
extends: 'x-foo'
});
~~~
定義了自定義元素以后,使用的時候,有兩種方法。一種是直接使用,另一種是間接使用,指定為某個現有元素是自定義元素的實例。
~~~
<!-- 直接使用 -->
<supper-button></supper-button>
<!-- 間接使用 -->
<button is="supper-button"></button>
~~~
總之,如果A元素繼承了B元素。那么,B元素的is屬性,可以指定B元素是A元素的一個實例。
### 添加屬性和方法
自定義元素的強大之處,就是可以在它上面定義新的屬性和方法。
~~~
var XFooProto = Object.create(HTMLElement.prototype);
var XFoo = document.registerElement('x-foo', {prototype: XFooProto});
~~~
上面代碼注冊了一個x-foo標簽,并且指明原型繼承HTMLElement.prototype。現在,我們就可以在原型上面,添加新的屬性和方法。
~~~
// 添加屬性
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');
}
}
})
});
~~~
### 回調函數
自定義元素的原型有一些屬性,用來指定回調函數,在特定事件發生時觸發。
* createdCallback:實例生成時觸發
* attachedCallback:實例插入HTML文檔時觸發
* detachedCallback:實例從HTML文檔移除時觸發
* attributeChangedCallback(attrName, oldVal, newVal):實例的屬性發生改變時(添加、移除、更新)觸發
下面是一個例子。
~~~
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});
~~~
利用回調函數,可以方便地在自定義元素中插入HTML語句。
~~~
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回調函數,生成實例時,該函數運行,插入如下的HTML語句。
~~~
<x-foo-with-markup>
<b>I'm an x-foo-with-markup!</b>
</x-foo-with-markup>
~~~
## Shadow DOM
所謂Shadow DOM指的是,瀏覽器將模板、樣式表、屬性、JavaScript代碼等,封裝成一個獨立的DOM元素。外部的設置無法影響到其內部,而內部的設置也不會影響到外部,與瀏覽器處理原生網頁元素(比如元素)的方式很像。Shadow DOM最大的好處有兩個,一是可以向用戶隱藏細節,直接提供組件,二是可以封裝內部樣式表,不會影響到外部。Chrome 35+支持Shadow DOM。
Shadow DOM元素必須依存在一個現有的DOM元素之下,通過createShadowRoot方法創造,然后將其插入該元素。
~~~
var shadowRoot = element.createShadowRoot();
shadowRoot.appendChild(document.body);
~~~
上面代碼創造了一個shadowRoot元素,然后將其插入HTML文檔。
下面的例子是指定網頁中某個現存的元素,作為Shadom DOM的根元素。
~~~
<button>Hello, world!</button>
<script>
var host = document.querySelector('button');
var root = host.createShadowRoot();
root.textContent = '你好';
</script>
~~~
上面代碼指定現存的button元素,為Shadow DOM的根元素,并將button的文字從英文改為中文。
通過innerHTML屬性,可以為Shadow DOM指定內容。
~~~
var shadow = document.querySelector('#hostElement').createShadowRoot();
shadow.innerHTML = '<p>Here is some new text</p>';
shadow.innerHTML += '<style>p { color: red };</style>';
~~~
下面的例子是為Shadow DOM加上獨立的模板。
~~~
<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>
~~~
上面代碼是一個div元素和模板。接下來,就是要把模板應用到div元素上。
~~~
var shadow = document.querySelector('#nameTag').createShadowRoot();
var template = document.querySelector('#nameTagTemplate');
shadow.appendChild(template.content.cloneNode());
~~~
上面代碼先用createShadowRoot方法,對div創造一個根元素,用來指定Shadow DOM,然后把模板元素添加為Shadow的子元素。
## HTML Import
### 基本操作
長久以來,網頁可以加載外部的樣式表、腳本、圖片、多媒體,卻無法方便地加載其他網頁,iframe和ajax都只能提供部分的解決方案,且有很大的局限。HTML Import就是為了解決加載外部網頁這個問題,而提出來的。
下面代碼用于測試當前瀏覽器是否支持HTML Import。
~~~
function supportsImports() {
return 'import' in document.createElement('link');
}
if (supportsImports()) {
// 支持
} else {
// 不支持
}
~~~
HTML Import用于將外部的HTML文檔加載進當前文檔。我們可以將組件的HTML、CSS、JavaScript封裝在一個文件里,然后使用下面的代碼插入需要使用該組件的網頁。
~~~
<link rel="import" href="dialog.html">
~~~
上面代碼在網頁中插入一個對話框組件,該組建封裝在`dialog.html`文件。注意,dialog.html文件中的樣式和JavaScript腳本,都對所插入的整個網頁有效。
假定A網頁通過HTML Import加載了B網頁,即B是一個組件,那么B網頁的樣式表和腳本,對A網頁也有效(準確得說,只有style標簽中的樣式對A網頁有效,link標簽加載的樣式表對A網頁無效)。所以可以把多個樣式表和腳本,都放在B網頁中,都從那里加載。這對大型的框架,是很方便的加載方法。
如果B與A不在同一個域,那么A所在的域必須打開CORS。
~~~
<!-- example.com必須打開CORS -->
<link rel="import" href="http://example.com/elements.html">
~~~
除了用link標簽,也可以用JavaScript調用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加載成功時,會在link元素上觸發load事件,加載失敗時(比如404錯誤)會觸發error事件,可以對這兩個事件指定回調函數。
~~~
<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函數的定義,必須在link元素的前面。因為瀏覽器元素遇到link元素時,立刻解析并加載外部網頁(同步操作),如果這時沒有對這兩個函數定義,就會報錯。
HTML Import是同步加載,會阻塞當前網頁的渲染,這主要是為了樣式表的考慮,因為外部網頁的樣式表對當前網頁也有效。如果想避免這一點,可以為link元素加上async屬性。當然,這也意味著,如果外部網頁定義了組件,就不能立即使用了,必須等HTML Import完成,才能使用。
~~~
<link rel="import" href="/path/to/import_that_takes_5secs.html" async>
~~~
但是,HTML Import不會阻塞當前網頁的解析和腳本執行(即阻塞渲染)。這意味著在加載的同時,主頁面的腳本會繼續執行。
最后,HTML Import支持多重加載,即被加載的網頁同時又加載其他網頁。如果這些網頁都重復加載同一個外部腳本,瀏覽器只會抓取并執行一次該腳本。比如,A網頁加載了B網頁,它們各自都需要加載jQuery,瀏覽器只會加載一次jQuery。
### 腳本的執行
外部網頁的內容,并不會自動顯示在當前網頁中,它只是儲存在瀏覽器中,等到被調用的時候才加載進入當前網頁。為了加載網頁網頁,必須用DOM操作獲取加載的內容。具體來說,就是使用link元素的import屬性,來獲取加載的內容。這一點與iframe完全不同。
~~~
var content = document.querySelector('link[rel="import"]').import;
~~~
發生以下情況時,link.import屬性為null。
* 瀏覽器不支持HTML Import
* link元素沒有聲明`rel="import"`
* link元素沒有被加入DOM
* link元素已經從DOM中移除
* 對方域名沒有打開CORS
下面代碼用于從加載的外部網頁選取id為template的元素,然后將其克隆后加入當前網頁的DOM。
~~~
var el = linkElement.import.querySelector('#template');
document.body.appendChild(el.cloneNode(true));
~~~
當前網頁可以獲取外部網頁,反過來也一樣,外部網頁中的腳本,不僅可以獲取本身的DOM,還可以獲取link元素所在的當前網頁的DOM。
~~~
// 以下代碼位于被加載(import)的外部網頁
// importDoc指向被加載的DOM
var importDoc = document.currentScript.ownerDocument;
// mainDoc指向主文檔的DOM
var mainDoc = document;
// 將子頁面的樣式表添加主文檔
var styles = importDoc.querySelector('link[rel="stylesheet"]');
mainDoc.head.appendChild(styles.cloneNode(true));
~~~
上面代碼將所加載的外部網頁的樣式表,添加進當前網頁。
被加載的外部網頁的腳本是直接在當前網頁的上下文執行,因為它的`window.document`指的是當前網頁的document,而且它定義的函數可以被當前網頁的腳本直接引用。
### Web Component的封裝
對于Web Component來說,HTML Import的一個重要應用是在所加載的網頁中,自動登記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; //指向被加載的網頁
// 定義并登記<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>
~~~
上面代碼定義并登記了兩個元素:和。在主頁面使用這兩個元素,非常簡單。
~~~
<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`,就可以在自己的頁面中使用了。
## Polymer.js
Web Components是非常新的技術,為了讓老式瀏覽器也能使用,Google推出了一個函數庫[Polymer.js](http://www.polymer-project.org/)。這個庫不僅可以幫助開發者,定義自己的網頁元素,還提供許多預先制作好的組件,可以直接使用。
### 直接使用的組件
Polymer.js提供的組件,可以直接插入網頁,比如下面的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>
~~~
再比如,在網頁中插入一個時鐘,可以直接使用下面的標簽。
~~~
<polymer-ui-clock></polymer-ui-clock>
~~~
自定義標簽與其他標簽的用法完全相同,也可以使用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這兩個核心部分。
~~~
bower install --save Polymer/platform
bower install --save Polymer/polymer
~~~
你還可以安裝所有預先定義的界面組件。
~~~
bower install Polymer/core-elements
bower install Polymer/polymer-ui-elements
~~~
還可以只安裝單個組件。
~~~
bower install Polymer/polymer-ui-accordion
~~~
這時,組件根目錄下的bower.json,會指明該組件的依賴的模塊,這些模塊會被自動安裝。
~~~
{
"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"
}
~~~
### 自定義組件
下面是一個最簡單的自定義組件的例子。
~~~
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="lorem-element">
<template>
<p>Lorem ipsum</p>
</template>
</polymer-element>
~~~
上面代碼定義了lorem-element組件。它分成三個部分。
(1)import命令
import命令表示載入核心模塊
(2)polymer-element標簽
polymer-element標簽定義了組件的名稱(注意,組件名稱中必須包含連字符)。它還可以使用extends屬性,表示組件基于某種網頁元素。
~~~
<polymer-element name="w3c-disclosure" extends="button">
~~~
(3)template標簽
template標簽定義了網頁元素的模板。
### 組件的使用方法
在調用組件的網頁中,首先加載polymer.js庫和組件文件。
~~~
<script src="components/platform/platform.js"></script>
<link rel="import" href="w3c-disclosure.html">
~~~
然后,分成兩種情況。如果組件不基于任何現有的HTML網頁元素(即定義的時候沒有使用extends屬性),則可以直接使用組件。
~~~
<lorem-element></lorem-element>
~~~
這時網頁上就會顯示一行字“Lorem ipsum”。
如果組件是基于(extends)現有的網頁元素,則必須在該種元素上使用is屬性指定組件。
~~~
<button is="w3c-disclosure">Expand section 1</button>
~~~
## 參考鏈接
* Todd Motto,?[Web Components and concepts, ShadowDOM, imports, templates, custom elements](http://toddmotto.com/web-components-concepts-shadow-dom-imports-templates-custom-elements/)
* Dominic Cooney,?[Shadow DOM 101](http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)
* Eric Bidelman,?[HTML's New Template Tag](http://www.html5rocks.com/en/tutorials/webcomponents/template/)
* Rey Bango,?[Using Polymer to Create Web Components](http://code.tutsplus.com/tutorials/using-polymer-to-create-web-components--cms-20475)
* Cédric Trévisan, Building an Accessible Disclosure Button – using Web Components]([http://blog.paciellogroup.com/2014/06/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](http://www.html5rocks.com/en/tutorials/webcomponents/customelements/)
* Eric Bidelman,?[HTML Imports](http://www.html5rocks.com/en/tutorials/webcomponents/imports/)
* TJ VanToll,?[Why Web Components Are Ready For Production](http://developer.telerik.com/featured/web-components-ready-production/)
* Chris Bateman,?[A No-Nonsense Guide to Web Components, Part 1: The Specs](http://cbateman.com/blog/a-no-nonsense-guide-to-web-components-part-1-the-specs/)
- 第一章 導論
- 1.1 前言
- 1.2 為什么學習JavaScript?
- 1.3 JavaScript的歷史
- 第二章 基本語法
- 2.1 語法概述
- 2.2 數值
- 2.3 字符串
- 2.4 對象
- 2.5 數組
- 2.6 函數
- 2.7 運算符
- 2.8 數據類型轉換
- 2.9 錯誤處理機制
- 2.10 JavaScript 編程風格
- 第三章 標準庫
- 3.1 Object對象
- 3.2 Array 對象
- 3.3 包裝對象和Boolean對象
- 3.4 Number對象
- 3.5 String對象
- 3.6 Math對象
- 3.7 Date對象
- 3.8 RegExp對象
- 3.9 JSON對象
- 3.10 ArrayBuffer:類型化數組
- 第四章 面向對象編程
- 4.1 概述
- 4.2 封裝
- 4.3 繼承
- 4.4 模塊化編程
- 第五章 DOM
- 5.1 Node節點
- 5.2 document節點
- 5.3 Element對象
- 5.4 Text節點和DocumentFragment節點
- 5.5 Event對象
- 5.6 CSS操作
- 5.7 Mutation Observer
- 第六章 瀏覽器對象
- 6.1 瀏覽器的JavaScript引擎
- 6.2 定時器
- 6.3 window對象
- 6.4 history對象
- 6.5 Ajax
- 6.6 同域限制和window.postMessage方法
- 6.7 Web Storage:瀏覽器端數據儲存機制
- 6.8 IndexedDB:瀏覽器端數據庫
- 6.9 Web Notifications API
- 6.10 Performance API
- 6.11 移動設備API
- 第七章 HTML網頁的API
- 7.1 HTML網頁元素
- 7.2 Canvas API
- 7.3 SVG 圖像
- 7.4 表單
- 7.5 文件和二進制數據的操作
- 7.6 Web Worker
- 7.7 SSE:服務器發送事件
- 7.8 Page Visibility API
- 7.9 Fullscreen API:全屏操作
- 7.10 Web Speech
- 7.11 requestAnimationFrame
- 7.12 WebSocket
- 7.13 WebRTC
- 7.14 Web Components
- 第八章 開發工具
- 8.1 console對象
- 8.2 PhantomJS
- 8.3 Bower:客戶端庫管理工具
- 8.4 Grunt:任務自動管理工具
- 8.5 Gulp:任務自動管理工具
- 8.6 Browserify:瀏覽器加載Node.js模塊
- 8.7 RequireJS和AMD規范
- 8.8 Source Map
- 8.9 JavaScript 程序測試
- 第九章 JavaScript高級語法
- 9.1 Promise對象
- 9.2 有限狀態機
- 9.3 MVC框架與Backbone.js
- 9.4 嚴格模式
- 9.5 ECMAScript 6 介紹
- 附錄
- 10.1 JavaScript API列表
- 草稿一:函數庫
- 11.1 Underscore.js
- 11.2 Modernizr
- 11.3 Datejs
- 11.4 D3.js
- 11.5 設計模式
- 11.6 排序算法
- 草稿二:jQuery
- 12.1 jQuery概述
- 12.2 jQuery工具方法
- 12.3 jQuery插件開發
- 12.4 jQuery.Deferred對象
- 12.5 如何做到 jQuery-free?
- 草稿三:Node.js
- 13.1 Node.js 概述
- 13.2 CommonJS規范
- 13.3 package.json文件
- 13.4 npm模塊管理器
- 13.5 fs 模塊
- 13.6 Path模塊
- 13.7 process對象
- 13.8 Buffer對象
- 13.9 Events模塊
- 13.10 stream接口
- 13.11 Child Process模塊
- 13.12 Http模塊
- 13.13 assert 模塊
- 13.14 Cluster模塊
- 13.15 os模塊
- 13.16 Net模塊和DNS模塊
- 13.17 Express框架
- 13.18 Koa 框架