Backbone.js為復雜WEB應用程序提供模型(models)、集合(collections)、視圖(views)的結構。其中模型用于綁定鍵值數據和自定義事件;集合附有可枚舉函數的豐富API; 視圖可以聲明事件處理函數,并通過RESRful JSON接口連接到應用程序。

此項目托管在 GitHub 上, 并且提供 帶注釋的源碼, 在線的 測試套件, 應用示例, 教程列表 還有一個 實際應用項目的超長列表這些項目都使用了 Backbone. Backbone 允許在 MIT 軟件協議 下使用.

你可以在GitHub issues 頁面#documentcloud頻道下的Freenode IRC中 報告 bug 和 討論功能, 在Google Groupwiki頁面中提出問題,或在twitter上 @documentcloud

Backbone是 DocumentCloud 的一個開源組件.

下載&依賴 (右鍵另存為)

開發版本 (1.1.2) 60kb, 完整的源代碼,大量的注釋
生產版本 (1.1.2) 6.5kb, 打包和gzip壓縮
(Source Map)
Edge Version (master) 未發布版本,使用風險自負

Backbone唯一重度依賴的是Underscore.js( >= 1.5.0)(手冊網注:Underscore.js 中文文檔請查看 http://www.css88.com/doc/underscore/)。基于RESTful(一個架構樣式的網絡系統)的約束,histroy的支持依賴于Backbone.Router ,DOM處理依賴于 Backbone.View,包括jQuery ( >= 1.11.0), 和 json2.js對舊的IE瀏覽器的支持。(模仿Underscore 和 jQuery 的APIs,例如 Lo-DashZepto,在不同的兼容性下也一樣能運行)

介紹(Introduction)

當我們開發含有大量Javascript的web應用程序時,首先你需要做的事情之一便是停止向DOM對象附加數據。 通過復雜多變的jQuery選擇符和回調函數很容易創建Javascript應用程序,包括在HTML UI,Javascript邏輯和數據之間保持同步,都不復雜。 但對富客戶端應用來說,良好的架構通常是有很多益處的。

通過Backbone,你可以將數據呈現為 Models, 你可以對模型進行創建,驗證和銷毀,以及將它保存到服務器。 任何時候只要UI事件引起模型內的屬性變化,模型會觸發"change"事件; 所有顯示模型數據的 Views 會接收到該事件的通知,繼而視圖重新渲染。 你無需查找DOM來搜索指定id的元素去手動更新HTML。 — 當模型改變了,視圖便會自動變化。

某種意義上說,在用javaScript來創建web項目時,Backbone試圖定義一組最小而高效的集合,包括了數據結構(models(模型) 和 collections(集合))和用戶接口(views(視圖) 和 URLS)。在web開發環境里,到處都是框架(幫你寫好了一切),不過這些庫需要你的網站在構建的時候符合該框架的樣子,風格,默認的行為。但是,Backbone還是作為一個工具,讓你可以隨心所欲的設計你的網站。

如果你不懂Backbone或者不確定Backbone能否幫助到你,先運行一下 列表中基于Backbone的項目

文檔下面有大量可以運行的例子,請點擊 play 執行他們。

升級到 1.1

從Backbone 0.9.X系列版本升級到 1.1 應該是相當容易的。如果你從舊版本升級, 一定要檢查更新日志。簡單地說,一些大規模的重大更改是:

  • 如果你想漂亮的更新一個Collection(集合)的內容,增加新的models(模型),刪除丟失,和合并那些已經存在,你現在可以調用set(以前叫做"update") ,Model(模型)類似的操作也調用set。這是目前默認的,當你在collection(集合)上調用fetch時。為了得到舊的行為,傳遞{reset: true}
  • 如果你的URL片段中有字符,需要URL編碼,Backbone現在會在你路由處理程序接收它們作為參數前為你解碼(跨瀏覽器規范的行為)。
  • 0.9.x中,Backbone 事件有了兩個新的方法:listenTostopListening, 這使得它能更容易地創建Views(視圖)監聽,當你想 remove view(視圖)時,解除他們所有綁定的監聽。
  • model(模型)驗證現在只默認執行在save中 —不再執行在set中,除非傳遞了{validate:true}選項。model(模型)驗證現在會觸發一個 "invalid"事件,而不是"error"事件。
  • 在1.1中 ,Backbone Views(視圖)不再有 options 參數自動附加在this.options上。如果你喜歡可以繼續附加。
  • 在1.1中 ,Collectionadd, remove, set, push, 和 shift 方法現在返回來自collection(集合)的 models(模型)(或 models)。

Backbone.Events(事件)

Events 是一個可以融合到任何對象的模塊, 給予 對象綁定和觸發自定義事件的能力. Events 在綁定之前 不需要聲明, 并且還可以傳遞參數. 比如:

var object = {};

_.extend(object, Backbone.Events);

object.on("alert", function(msg) {
  alert("Triggered " + msg);
});

object.trigger("alert", "an event");

舉個例子, 你可以定義一個事件調度程序,然后在你應用的不同地方調用,例如: var dispatcher = _.clone(Backbone.Events)

onobject.on(event, callback, [context])別名: bind
在 object 上綁定一個callback回調函數。 只要event觸發,該回調函數就會調用。如果你的一個頁面含有大量的不同時間,我們約定使用冒號來為事件添加 命名空間 俗成地使用冒號來命名:"poll:start", 或 "change:selection"。 事件字符串也可能是用空格分隔的多個事件列表(手冊網注:即可以同時綁定多個事件,事件用空格分隔)...

book.on("change:title change:author", ...);

當回調函數被調用時,通過可選的第三個參數可以為this提供一個context(上下文)值:model.on('change', this.render, this) (手冊網注:即回調函數中的This,指向傳遞的第三個參數)。

當回調函數被綁定到特殊"all"事件時,任何事件的發生都會觸發該回調函數,回調函數的第一個參數會傳遞該事件的名稱。舉個例子,將一個對象的所有事件代理到另一對象:

proxy.on("all", function(eventName) {
  object.trigger(eventName);
});

所有Backbone事件方法還支持事件映射的語法, 作為可惜的位置參數:

book.on({
  "change:title": titleView.update,
  "change:author": authorPane.update,
  "destroy": bookView.remove
});

offobject.off([event], [callback], [context])別名: unbi nd
從 object 對象移除先前綁定的 callback 函數。如果沒有指定context(上下文),所有上下文下的這個回調函數將被移除。如果沒有指定callback,所有綁定這個事件回調函數將被移除;如果沒有指定event,所有事件的回調函數會被移除。

// Removes just the `onChange` callback.
object.off("change", onChange);

// Removes all "change" callbacks.
object.off("change");

// Removes the `onChange` callback for all events.
object.off(null, onChange);

// Removes all callbacks for `context` for all events.
object.off(null, null, context);

// Removes all callbacks on `object`.
object.off();

需要注意的是,調用 model.off(),例如,這確實會刪除model(模型)上所有的事件—包括Backbone內部用來統計的事件。

triggerobject.trigger(event, [*args])
觸發給定 event或用空格隔開的事件的回調函數。后續傳入 trigger 的參數會傳遞到觸發事件的回調函數里。

onceobject.once(event, callback, [context])
用法跟on很像,區別在于綁定的回調函數觸發一次后就會被移除(手冊網注:只執行一次)。簡單的說就是“下次不在觸發了,用這個方法”。

listenToobject.listenTo(other, event, callback)
object 監聽 另一個(other)對象上的一個特定事件。不使用other.on(event, callback, object),而使用這種形式的優點是:listenTo允許 object來跟蹤這個特定事件,并且以后可以一次性全部移除它們。callback總是在object上下文環境中被調用。

view.listenTo(model, 'change', view.render);

stopListeningobject.stopListening([other], [event], [callback])
object 停止監聽事件。如果調用不帶參數的stopListening,可以移除 object 下所有已經registered(注冊)的callback函數...,或者只刪除指定對象上明確告知的監聽事件,或者一個刪除指定事件,或者只刪除指定的回調函數。

view.stopListening();

view.stopListening(model);

listenToOnceobject.listenToOnce(other, event, callback)
用法跟 listenTo 很像,但是事件觸發一次后callback將被移除。

Catalog of Events(事件目錄)
下面是Backbone 內置事件的完整列表,帶有參數。 你也可以在Models(模型),Collection(集合),Views(視圖)上自由地觸發這些事件,只要你認為合適。 收藏和意見,你認為合適。 Backbone 對象本身混入了Events,并且可用于觸發任何全局事件,只要您的應用程序的需要。

  • "add" (model, collection, options) — 當一個model(模型)被添加到一個collection(集合)時觸發。
  • "remove" (model, collection, options) — 當一個model(模型)從一個collection(集合)中被刪除時觸發。
  • "reset" (collection, options) — 當該collection(集合)的全部內容已被替換時觸發。
  • "sort" (collection, options) — 當該collection(集合)已被重新排序時觸發。
  • "change" (model, options) — 當一個model(模型)的屬性改變時觸發。
  • "change:[attribute]" (model, value, options) — 當一個model(模型)的某個特定屬性被更新時觸發。
  • "destroy" (model, collection, options) —當一個model(模型)被destroyed(銷毀)時觸發。
  • "request" (model_or_collection, xhr, options) — 當一個model(模型)或collection(集合)開始發送請求到服務器時觸發。
  • "sync" (model_or_collection, resp, options) — 當一個model(模型)或collection(集合)成功同步到服務器時觸發。
  • "error" (model_or_collection, resp, options) — 當一個model(模型)或collection(集合)的請求遠程服務器失敗時觸發。
  • "invalid" (model, error, options) — 當model(模型)在客戶端 validation(驗證)失敗時觸發。
  • "route:[name]" (params) —  當一個特定route(路由)相匹配時通過路由器觸發。
  • "route" (route, params) — 當任何一個route(路由)相匹配時通過路由器觸發。
  • "route" (router, route, params) — 當任何一個route(路由)相匹配時通過history(歷史記錄)觸發。
  • "all" — 所有事件發生都能觸發這個特別的事件,第一個參數是觸發事件的名稱。

一般來說,事件觸發(例如model.set,collection.add或者其他事件)后就會執行回調函數,但是如果你想阻止回調函數的執行,你可以傳遞{silent: true}作為參數。很多時候,這是一個好的方法。通過在回調函數里傳輸一個特定的判斷參數,會讓你的程序更加出色。 一般而言,事件觸發(model.set, collection.add,等等...)后就會調用一個函數,但是如果你想阻止事件被觸發, 您可以傳遞{silent: true}作為一個選項。注意,這中情況很少, 甚至從來沒有, 一個好主意。 通過在選項中傳遞一個特定的標記,回調函數里傳輸一個特定的判斷參數 并且選擇忽略,會讓你的程序更加出色。

Backbone.Model(模型)

Models(模型)是任何Javascript應用的核心,包括數據交互及與其相關的大量邏輯: 轉換、驗證、計算屬性和訪問控制。你可以用特定的方法擴展 Backbone.ModelModel 也提供了一組基本的管理變化的功能。

下面的示例演示了如何定義一個模型,包括自定義方法、設置屬性、以及觸發該屬性變化的事件。一旦運行此代碼后,sidebar在瀏覽器的控制臺就可用,這樣你就可以充分發揮了。

var Sidebar = Backbone.Model.extend({
  promptColor: function() {
    var cssColor = prompt("Please enter a CSS color:");
    this.set({color: cssColor});
  }
});

window.sidebar = new Sidebar;

sidebar.on('change:color', function(model, color) {
  $('#sidebar').css({background: color});
});

sidebar.set({color: 'white'});

sidebar.promptColor();

extendBackbone.Model.extend(properties, [classProperties])
要創建自己的 Model 類,你可以擴展 Backbone.Model 并提供實例 properties(屬性) , 以及可選的可以直接注冊到構造函數的classProperties(類屬性)

extend 可以正確的設置原型鏈,因此通過 extend 創建的子類 (subclasses) 也可以被深度擴展。

var Note = Backbone.Model.extend({

  initialize: function() { ... },

  author: function() { ... },

  coordinates: function() { ... },

  allowedToEdit: function(account) {
    return true;
  }

});

var PrivateNote = Note.extend({

  allowedToEdit: function(account) {
    return account.owns(this);
  }

});

父類(super) 的簡述:Javascript沒有提供一種直接調用父類的方式 — 如果你要重載原型鏈中上層定義的同名函數,如 set, 或 save , 并且你想調用父對象的實現,這時需要明確的調用它,類似這樣:

var Note = Backbone.Model.extend({
  set: function(attributes, options) {
    Backbone.Model.prototype.set.apply(this, arguments);
    ...
  }
});

constructor / initializenew Model([attributes], [options])
當創建model實例時,可以傳入 屬性 (attributes)初始值,這些值會被 set (設置)到 model。 如果定義了 initialize 函數,該函數會在model創建后執行。

new Book({
  title: "One Thousand and One Nights",
  author: "Scheherazade"
});

在極少數的情況下,你可能需要去重寫 constructor ,它可以讓你替換你的model的實際構造函數。

var Library = Backbone.Model.extend({
  constructor: function() {
    this.books = new Books();
    Backbone.Model.apply(this, arguments);
  },
  parse: function(data, options) {
    this.books.reset(data.books);
    return data.library;
  }
});

如果你傳入{collection: ...} ,這個 options表示這個model屬于哪個collection,且用于計算這個model的url。否則model.collection 這個屬性會在你第一次添加model到一個collection的時候被自動添加。 需要注意的是相反的是不正確的,因為傳遞這個選項給構造函數將不會自動添加model到集合。有時這個是很有用的。

如果{parse: true}被作為一個option選項傳遞, attributes將在 set到model之前首先通過parse被轉換。

getmodel.get(attribute)
從當前model中獲取當前屬性(attributes)值,比如: note.get("title")

setmodel.set(attributes, [options])
向model設置一個或多個hash屬性(attributes)。如果任何一個屬性改變了model的狀態,在不傳入 {silent: true} 選項參數的情況下,會觸發 "change" 事件,更改特定屬性的事件也會觸發。 可以綁定事件到某個屬性,例如:change:title,及 change:content

note.set({title: "March 20", content: "In his eyes she eclipses..."});

book.set("title", "A Scandal in Bohemia");

escapemodel.escape(attribute)
get 類似,只是返回的是HTML轉義后版本的model屬性值。如果從model插入數據到HTML,使用 escape 取數據可以避免 XSS 攻擊。

var hacker = new Backbone.Model({
  name: "<script>alert('xss')</script>"
});

alert(hacker.escape('name'));

hasmodel.has(attribute)
屬性值為非 null 或非 undefined 時返回 true

if (note.has("title")) {
  ...
}

unsetmodel.unset(attribute, [options])
從內部屬性散列表中刪除指定屬性(attribute)。 如果未設置 silent 選項,會觸發 "change" 事件。

clearmodel.clear([options])
從model中刪除所有屬性, 包括id屬性。 如果未設置 silent 選項,會觸發 "change" 事件。

idmodel.id
id是model的特殊屬性,可以是任意字符串(整型 id 或 UUID)。在屬性中設置的 id 會被直接拷貝到model屬性上。 我們可以從集合(collections)中通過 id 獲取model,另外 id 通常用于生成model的 URLs。

idAttributemodel.idAttribute
一個model的唯一標示符,被儲存在 id 屬性下。如果使用一個不同的唯一的key直接和后端通信。可以設置Model的 idAttribute 到一個從key到 id 的一個透明映射中。

var Meal = Backbone.Model.extend({
  idAttribute: "_id"
});

var cake = new Meal({ _id: 1, name: "Cake" });
alert("Cake id: " + cake.id);

cidmodel.cid
model的特殊屬性,cid 或客戶 id 是當所有model創建時自動產生的唯一標識符。 客戶 ids 在model尚未保存到服務器之前便存在,此時model可能仍不具有最終的 id, 但已經需要在用戶界面可見。

attributesmodel.attributes
attributes 屬性是包含模型狀態的內部散列表 — 通常(但不一定)JSON對象的形式表示在服務器上模型數據 。它通常是數據庫中一個行的簡單的序列,但它也可以是客戶端的計算狀態。

建議采用 set 更新 attributes而不要直接修改。  如果您想檢索和獲取模型屬性的副本, 用 _.clone(model.attributes) 取而代之。

由于這樣的事實: Events(事件)接受空格分隔事件列表, 但是屬性名稱不應該包括空格。

changedmodel.changed
changed屬性是一個包含所有屬性的內部散列,自最后 set 已改變。 自最后一組已改變。 請不要直接更新 changed,因為它的狀態是由set內部維護。 changed的副本可從changedAttributes獲得。

defaultsmodel.defaults or model.defaults()
defaults 散列(或函數)用于為模型指定默認屬性。 創建模型實例時,任何未指定的屬性會被設置為其默認值。

var Meal = Backbone.Model.extend({
  defaults: {
    "appetizer":  "caesar salad",
    "entree":     "ravioli",
    "dessert":    "cheesecake"
  }
});

alert("Dessert will be " + (new Meal).get('dessert'));

需要提醒的是,在 Javascript 中,對象是按引用傳值的,因此如果包含一個對象作為默認值,它會被所有實例共享。可以定義 defaults為一個函數取代。

toJSONmodel.toJSON([options])
返回一個模型的 attributes 淺拷貝副本的 JSON 字符串化形式。 它可用于模型的持久化、序列化,或者發送到服務之前的擴充。 該方法名稱比較混亂,因為它事實上并不返回 JSON 字符串, 但這是對 JavaScript API 的 JSON.stringify 實現。

var artist = new Backbone.Model({
  firstName: "Wassily",
  lastName: "Kandinsky"
});

artist.set({birthday: "December 16, 1866"});

alert(JSON.stringify(artist));

syncmodel.sync(method, model, [options])
使用 Backbone.sync 可以將一個模型的狀態持續發送到服務器。 可以自定義行為覆蓋。

fetchmodel.fetch([options])
通過委托給jqXHR。 如果模型從未填充數據時非常有用, 或者如果你想確保你有最新的服務器狀態。 如果服務器的狀態不同于當前屬性的"change"事件將被觸發。 接受 successerror回調的選項散列, 這兩個回調都可以傳遞(model, response, options)作為參數。

// 每隔 10 秒從服務器拉取數據以保持頻道模型是最新的
setInterval(function() {
  channel.fetch();
}, 10000);

savemodel.save([attributes], [options])
通過委托給Backbone.sync,保存模型到數據庫(或替代持久化層)。 如果驗證成功,返回jqXHR,否則為 falseattributes散列(如set)應包含你想改變的屬性 - 不涉及的鍵不會被修改 - 但是,該資源的一個完整表示將被發送到服務器。 至于set,你可能會傳遞單獨的鍵和值,而不是一個哈希值。 如果模型有一個validate方法,并且驗證失敗, 該模型將不會被保存。 如果模型isNew, 保存將采用"create"(HTTP POST), 如果模型在服務器上已經存在, 保存將采用"update"(HTTP PUT)。

相反,如果你只想將改變屬性發送到服務器, 調用model.save(attrs, {patch: true})。 你會得到一個HTTP PATCH請求將剛剛傳入的屬性發送到服務器。

通過新的屬性調用save 將立即觸發一個"change"事件,一個"request"事件作為Ajax請求開始到服務器, 并且當服務器確認成功修改后立即觸發 一個"sync"事件。 如果你想在模型上等待服務器設置新的屬性,請傳遞{wait: true}

在下面的例子中, 注意我們如何覆蓋Backbone.sync的版本,在模型初次保存時接收到 "create"請求,第二次接收到 "update" 請求的。

Backbone.sync = function(method, model) {
  alert(method + ": " + JSON.stringify(model));
  model.set('id', 1);
};

var book = new Backbone.Model({
  title: "The Rough Riders",
  author: "Theodore Roosevelt"
});

book.save();

book.save({author: "Teddy"});

save 支持在選項散列表中傳入 successerror 回調函數, 回調函數支持傳入 (model, response, options) 作為參數。 如果服務端驗證失敗,返回非 200 的 HTTP 響應碼,將產生文本或 JSON 的錯誤內容。

book.save("author", "F.D.R.", {error: function(){ ... }});

destroymodel.destroy([options])
通過委托給Backbone.sync,保存模型到數據庫(或替代持久化層)。 通過委托一個HTTP DELETE請求給Backbone.sync破壞服務器上的模型。 返回一個jqXHR對象, 或者如果模型isNew,那么返回false。 選項散列表中接受 successerror 回調函數, 回調函數支持傳入 (model, response, options) 作為參數。 在模型上觸發 "destroy" 事件,該事件將會冒泡到任何包含這個模型的集合中, 一個"request"事件作為Ajax請求開始到服務器, 并且當服務器確認模型被刪除后立即觸發 一個"sync"事件。如果你想在集合中刪除這個模型前等待服務器相應,請傳遞{wait: true}

book.destroy({success: function(model, response) {
  ...
}});

Underscore 方法 (6)
Backbone 代理了 Underscore.js用來給Backbone.Model提供 6 個對象函數。這里沒有完全記錄他們,但你可以看看Underscore文檔中全部詳情… (手冊網注:下面鏈接已經替換成中文文檔的地址)

user.pick('first_name', 'last_name', 'email');

chapters.keys().join(', ');

validatemodel.validate(attributes, options)
這種方法是未定義的, 如果您有任何可以在JavaScript中執行的代碼 并且我們鼓勵你用你自定義驗證邏輯覆蓋它 。 默認情況下validatesave之前調用, 但如果傳遞了 {validate:true},也可以在set之前調用。 validate方法是通過模型的屬性,  選項和setsave是一樣的。 如果屬性是有效的, validate不返回驗證任何東西;  如果它們是無效的, 返回一個你選擇的錯誤。 它可以是一個用來顯示的簡單的字符串錯誤信息, 或一個以編程方式描述錯誤的完整錯誤對象。 如果validate返回一個錯誤, save不會繼續, 并且在服務器上該模型的屬性將不被修改。 校驗失敗將觸發"invalid"事件, 并用此方法返回的值設置模型上的validationError屬性。

var Chapter = Backbone.Model.extend({
  validate: function(attrs, options) {
    if (attrs.end < attrs.start) {
      return "can't end before it starts";
    }
  }
});

var one = new Chapter({
  title : "Chapter One: The Beginning"
});

one.on("invalid", function(model, error) {
  alert(model.get("title") + " " + error);
});

one.save({
  start: 15,
  end:   10
});

"invalid"事件提供粗粒度的錯誤信息 在模型或集合層面上是很有用。

validationErrormodel.validationError
validate最后驗證失敗時返回的值。

isValidmodel.isValid()
運行validate來檢查模型狀態。

var Chapter = Backbone.Model.extend({
  validate: function(attrs, options) {
    if (attrs.end < attrs.start) {
      return "can't end before it starts";
    }
  }
});

var one = new Chapter({
  title : "Chapter One: The Beginning"
});

one.set({
  start: 15,
  end:   10
});

if (!one.isValid()) {
  alert(one.get("title") + " " + one.validationError);
}

urlmodel.url()
返回模型資源在服務器上位置的相對 URL 。 如果模型放在其它地方,可通過合理的邏輯重載該方法。 生成 URLs 的默認形式為:"/[collection.url]/[id]", 如果模型不是集合的一部分,你可以通過指定明確的urlRoot覆蓋。

由于是委托到 Collection#url 來生成 URL, 所以首先需要確認它是否定義過,或者所有模型共享一個通用根 URL 時,是否存在 urlRoot 屬性。 例如,一個 id 為 101 的模型,存儲在 url"/documents/7/notes"Backbone.Collection 中, 那么該模型的 URL 為:"/documents/7/notes/101"

urlRootmodel.urlRoot or model.urlRoot()
如果使用的集合外部的模型,通過指定 urlRoot 來設置生成基于模型 id 的 URLs 的默認 url 函數。 "[urlRoot]/id"。通常情況下,你不會需要定義這一點。 需要注意的是urlRoot也可以是一個函數。

var Book = Backbone.Model.extend({urlRoot : '/books'});

var solaris = new Book({id: "1083-lem-solaris"});

alert(solaris.url());

parsemodel.parse(response, options)
parse 會在通過 fetch 從服務器返回模型數據,以及 save 時執行。 傳入本函數的為原始 response 對象,并且應當返回可以 set 到模型的屬性散列表。 默認實現是自動進行的,僅簡單傳入 JSON 響應。 如果需要使用已存在的 API,或者更好的命名空間響應,可以重載它。

如果使用的3.1版本之前的 Rails 后端,需要注意 Rails's 默認的 to_json 實現已經包含了命名空間之下的模型屬性。 對于無縫的后端集成環境禁用這種行為:

ActiveRecord::Base.include_root_in_json = false

clonemodel.clone()
返回該模型的具有相同屬性的新實例。

isNewmodel.isNew()
模型是否已經保存到服務器。 如果模型尚無 id,則被視為新的。

hasChangedmodel.hasChanged([attribute])
標識模型從上次 set 事件發生后是否改變過。 如果傳入 attribute ,當指定屬性改變后返回 true

注意,本方法以及接下來 change 相關的方法,僅對 "change"事件發生有效。

book.on("change", function() {
  if (book.hasChanged("title")) {
    ...
  }
});

changedAttributesmodel.changedAttributes([attributes])
只從最后一次set開始檢索已改變的模型屬性散列(hash),  或者如果沒有,返回 false。 作為可選,可以傳遞外部屬性哈希(hash), 返回與該模型不同的屬性的哈希(hash)。 這可以用來找出視圖的哪些部分應該更新,或者確定哪些需要與服務器進行同步。

previousmodel.previous(attribute)
"change" 事件發生的過程中,本方法可被用于獲取已改變屬性的舊值。

var bill = new Backbone.Model({
  name: "Bill Smith"
});

bill.on("change:name", function(model, name) {
  alert("Changed name from " + bill.previous("name") + " to " + name);
});

bill.set({name : "Bill Jones"});

previousAttributesmodel.previousAttributes()
返回模型的上一個屬性的副本。一般用于獲取模型的不同版本之間的區別,或者當發生錯誤時回滾模型狀態。

Backbone.Collection(集合)

集合是模型的有序組合,我們可以在集合上綁定 "change" 事件,從而當集合中的模型發生變化時fetch(獲得)通知,集合也可以監聽 "add""remove" 事件, 從服務器更新,并能使用 Underscore.js 提供的方法。

集合中的模型觸發的任何事件都可以在集合身上直接觸發,所以我們可以監聽集合中模型的變化: documents.on("change:selected", ...)

extendBackbone.Collection.extend(properties, [classProperties])
通過擴展 Backbone.Collection 創建一個 Collection 類。實例屬性參數 properties 以及 類屬性參數 classProperties 會被直接注冊到集合的構造函數。

modelcollection.model
覆蓋此屬性來指定集合中包含的模型類。可以傳入原始屬性對象(和數組)來 add, create,和 reset,傳入的屬性會被自動轉換為適合的模型類型。

var Library = Backbone.Collection.extend({
  model: Book
});

集合也可以包含多態模型,通過用構造函數重寫這個屬性,返回一個模型。

var Library = Backbone.Collection.extend({

  model: function(attrs, options) {
    if (condition) {
      return new PublicDocument(attrs, options);
    } else {
      return new PrivateDocument(attrs, options);
    }
  }

});

constructor / initializenew Backbone.Collection([models], [options])
當創建集合時,你可以選擇傳入初始的 models 數組。 集合的 comparator 函數也可以作為選項傳入。 傳遞false作為comparator選項將阻止排序。 如果定義了 initialize 函數,會在集合創建時被調用。 有幾個選項, 如果提供的話,將直接附加到集合上:modelcomparator
通過傳遞nullmodels選項來創建一個空的集合。

var tabs = new TabSet([tab1, tab2, tab3]);
var spaces = new Backbone.Collection([], {
  model: Space
});

modelscollection.models
訪問集合中模型的內置的JavaScript 數組。通常我們使用 getat,或 Underscore方法 訪問模型對象,但偶爾也需要直接訪問。

toJSONcollection.toJSON([options])
返回集合中包含的每個模型(通過 toJSON) 的屬性哈希的數組。可用于集合的序列化和持久化。本方法名稱容易引起混淆,因為它與 JavaScript's JSON API 命名相同。

var collection = new Backbone.Collection([
  {name: "Tim", age: 5},
  {name: "Ida", age: 26},
  {name: "Rob", age: 55}
]);

alert(JSON.stringify(collection));

synccollection.sync(method, collection, [options])
使用 Backbone.sync來將一個集合的狀態持久化到服務器。 可以自定義行為覆蓋。

Underscore 方法 (32)
Backbone 代理了 Underscore.js用來給Backbone.Collection提供 6 個對象函數。這里沒有完全記錄他們,但你可以看看Underscore文檔中全部詳情…(手冊網注:下面鏈接已經替換成中文文檔的地址)

books.each(function(book) {
  book.publish();
});

var titles = books.map(function(book) {
  return book.get("title");
});

var publishedBooks = books.filter(function(book) {
  return book.get("published") === true;
});

var alphabetical = books.sortBy(function(book) {
  return book.author.get("name").toLowerCase();
});

addcollection.add(models, [options])
向集合中增加一個模型(或一個模型數組),觸發"add"事件。  如果已經定義了model屬性, 您也可以通過原始屬性的對象讓其看起來像一個模型實例。 返回已經添加的(或預先存在的,如果重復)模式。  傳遞{at: index}可以將模型插入集合中特定的index索引位置。 如果您要添加 集合中已經存在的模型 到集合,他們會被忽略, 除非你傳遞{merge: true}, 在這種情況下,它們的屬性將被合并到相應的模型中, 觸發任何適當的"change" 事件。

var ships = new Backbone.Collection;

ships.on("add", function(ship) {
  alert("Ahoy " + ship.get("name") + "!");
});

ships.add([
  {name: "Flying Dutchman"},
  {name: "Black Pearl"}
]);

請注意,添加相同的模型(具有相同id的模型)到一個集合,一次以上
是空操作。

removecollection.remove(models, [options])
從集合中刪除一個模型(或一個模型數組),并且返回他們。會觸發 "remove" 事件,同樣可以使用 silent 關閉。移除前該模型的index可用作options.index類監聽。

resetcollection.reset([models], [options])
每次都是只添加和刪除一個模型那沒問題, 但有時,你需要改變很多模型,那么你寧愿只更新集合。  使用reset,將一個新的模型(或屬性散列)列表替換集合,最后觸發一個但單獨的"reset"事件。 到與模型的新列表替換集合(或屬性散列),觸發一個單一的“復位”事件在末端。 返回新的模型集合。 為方便起見, 在一個 "reset"事件中, 任何以前的模型列表可作為options.previousModels
通過傳遞nullmodels選項來清空你的集合。

下面是一個例子 使用reset來引導一個集合在頁面初始化時加載, 在Rails應用程序中:

<script>
  var accounts = new Backbone.Collection;
  accounts.reset(<%= @accounts.to_json %>);
</script>

調用collection.reset(),不傳遞任何模型作為參數 將清空整個集合。

setcollection.set(models, [options])
set方法通過傳遞模型列表執行一個集合的"smart(智能)"的更新。 如果列表中的一個模型尚不在集合中,那么它將被添加; 如果模型已經在集合中,其屬性將被合并; 并且如果集合包含存在于列表中的任何模型,他們將被刪除。 以上所有將觸發相應的"add", "remove", 和 "change"事件。 返回集合中的模型。 如果您想自定義的行為, 你可以設置選項:{add: false}, {remove: false}, 或 {merge: false},將其禁用。

var vanHalen = new Backbone.Collection([eddie, alex, stone, roth]);

vanHalen.set([eddie, alex, stone, hagar]);

// Fires a "remove" event for roth, and an "add" event for "hagar".
// Updates any of stone, alex, and eddie's attributes that may have
// changed over the years.

getcollection.get(id)
通過一個id,一個cid,或者傳遞一個model來 獲得集合中 的模型。

var book = library.get(110);

atcollection.at(index)
獲得集合中指定索引的模型。不論你是否對模型進行了重新排序, at 始終返回其在集合中插入時的索引值。

pushcollection.push(model, [options])
在集合尾部添加一個模型。選項和add相同。

popcollection.pop([options])
刪除并且返回集合中最后一個模型。選項和remove相同。

unshiftcollection.unshift(model, [options])
在集合開始的地方添加一個模型。選項和add相同。

shiftcollection.shift([options])
刪除并且返回集合中第一個模型。選項和remove相同。

slicecollection.slice(begin, end)
返回一個集合的模型的淺拷貝副本,使用與原生Array#slice相同的選項。

lengthcollection.length
與數組類似,集合擁有 length 屬性,返回該集合包含的模型數量。

comparatorcollection.comparator
默認情況下,集合沒有聲明 comparator 函數。如果定義了該函數,集合中的模型會按照指定的算法進行排序。 換言之,被增加模型,會被插入 collection.models中適合的位置。 comparator可以被定義為sortBy(傳遞帶有一個參數的函數),  作為一個sort(傳遞一個一個參數函數需要兩個參數), 或者作為一個表示屬性的字符串進行排序。

"sortBy"比較函數接受一個模型,并且返回一個該模型相對于其他模型的排序數字或字符串值。  "sort"比較函數接受兩個模型,并且,如果第一個模型應該在第二模型個之前,返回-1; 如果他們是同一等級的,返回0; 如果第一個模型應該在第二模型個之后,返回1需要注意的是 Backbone 這兩種風格的比較功能的確定 取決于參數個數。所以如果你綁定了比較函數,需要格外小心。

注意即使下面例子中的 chapters 是后加入到集合中的,但它們都會遵循正確的排序:

var Chapter  = Backbone.Model;
var chapters = new Backbone.Collection;

chapters.comparator = 'page';

chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));

alert(chapters.pluck('title'));

如果以后更改模型屬性,帶有比較函數的集合不會自動重新排序。 所以你不妨改變模型的屬性后調用sort, 這會影響排序。

sortcollection.sort([options])
強制對集合進行重排序。一般情況下不需要調用本函數,因為當一個模型被添加時, comparator 函數會實時排序。要禁用添加模型時的排序,可以傳遞{sort: false}add。 調用sort會觸發的集合的"sort"事件。

pluckcollection.pluck(attribute)
從集合中的每個模型中拉取 attribute(屬性)。等價于調用 map,并從迭代器中返回單個屬性。

var stooges = new Backbone.Collection([
  {name: "Curly"},
  {name: "Larry"},
  {name: "Moe"}
]);

var names = stooges.pluck("name");

alert(JSON.stringify(names));

wherecollection.where(attributes)
返回集合中所有匹配所傳遞 attributes(屬性)的模型數組。 對于簡單的filter(過濾)比較有用。

var friends = new Backbone.Collection([
  {name: "Athos",      job: "Musketeer"},
  {name: "Porthos",    job: "Musketeer"},
  {name: "Aramis",     job: "Musketeer"},
  {name: "d'Artagnan", job: "Guard"},
]);

var musketeers = friends.where({job: "Musketeer"});

alert(musketeers.length);

findWherecollection.findWhere(attributes)
就像where, 不同的是findWhere直接返回匹配所傳遞 attributes(屬性)的第一個模型。

urlcollection.url or collection.url()
設置 url 屬性(或函數)以指定集合對應的服務器位置。集合內的模型使用 url 構造自身的 URLs。

var Notes = Backbone.Collection.extend({
  url: '/notes'
});

// Or, something more sophisticated:

var Notes = Backbone.Collection.extend({
  url: function() {
    return this.document.url() + '/notes';
  }
});

parsecollection.parse(response, options)
每一次調用 fetch 從服務器拉取集合的模型數據時,parse都會被調用。 本函數接收原始 response 對象,返回可以 added(添加) 到集合的模型屬性數組。 默認實現是無需操作的,只需簡單傳入服務端返回的JSON對象。 如果需要處理遺留API,或者在返回數據定義自己的命名空間,可以重寫本函數。

var Tweets = Backbone.Collection.extend({
  // The Twitter Search API returns tweets under "results".
  parse: function(response) {
    return response.results;
  }
});

clonecollection.clone()
返回一個模型列表完全相同的集合新實例。

fetchcollection.fetch([options])
從服務器拉取集合的默認模型設置 ,成功接收數據后會setting(設置)集合。 options 支持 successerror 回調函數,兩個回調函數接收 (collection, response, options)作為參數。當模型數據從服務器返回時, 它使用 set來(智能的)合并所獲取到的模型, 除非你傳遞了 {reset: true}, 在這種情況下,集合將(有效地)重置。 可以委托Backbone.sync 在幕后自定義持久性策略 并返回一個jqXHR。 fetch請求的服務器處理器應該返回模型JSON數組。

Backbone.sync = function(method, model) {
  alert(method + ": " + model.url);
};

var accounts = new Backbone.Collection;
accounts.url = '/accounts';

accounts.fetch();

fetch行為可以通過使用有效的set選項進行定制。 例如,要獲取一個集合,每一個新的模型會得到一個 "add"事件,和每改變現有的模型的 "change"事件, 不刪除任何東西: collection.fetch({remove: false})

jQuery.ajax選項也可以直接傳遞作為 fetch選項, 所以要獲取一個分頁集合的特定頁面使用:Documents.fetch({data: {page: 3}})

需要注意的是 fetch 不應該被用來在頁面加載完畢時填充集合數據 — 所有頁面初始數據應當在 bootstrapped 時已經就緒。 fetch 適用于惰性加載不需立刻展現的模型數據:例如:例如文檔中 可切換打開和關閉的選項卡內容。

createcollection.create(attributes, [options])
方便的在集合中創建一個模型的新實例。 相當于使用屬性哈希(鍵值對象)實例化一個模型, 然后將該模型保存到服務器, 創建成功后將模型添加到集合中。 返回這個新模型。 如果客戶端驗證失敗,該模型將不會被保存, 與驗證錯誤。 為了能正常運行,需要在集合中設置 model 屬性。 create 方法接收鍵值對象或者已經存在尚未保存的模型對象作為參數。

創建一個模型將立即觸發集合上的"add"事件, 一個"request"的事件作為新的模型被發送到服務器, 還有一個 "sync" ”事件,一旦服務器響應成功創建模型。 如果你想在集合中添加這個模型前等待服務器相應,請傳遞{wait: true}

var Library = Backbone.Collection.extend({
  model: Book
});

var nypl = new Library;

var othello = nypl.create({
  title: "Othello",
  author: "William Shakespeare"
});

Backbone.Router(路由)

web應用程序通常需要為應用的重要位置提供可鏈接,可收藏,可分享的 URLs。 直到最近, 貓點(hash)片段(#page)可以被用來提供這種鏈接, 同時隨著 History API 的到來,貓點已經可以用于處理標準 URLs (/page)。 Backbone.Router 為客戶端路由提供了許多方法,并能連接到指定的動作(actions)和事件(events)。 對于不支持 History API 的舊瀏覽器,路由提供了優雅的回調函數并可以透明的進行 URL 片段的轉換。

頁面加載期間,當應用已經創建了所有的路由,需要調用 Backbone.history.start(),或 Backbone.history.start({pushState: true}) 來確保驅動初始化 URL 的路由。

extendBackbone.Router.extend(properties, [classProperties])
開始創建一個自定義的路由類。當匹配了 URL 片段便執行定義的動作,并可以通過 routes 定義路由動作鍵值對。 請注意,你要避免在路由定義時使用前導斜杠:

var Workspace = Backbone.Router.extend({

  routes: {
    "help":                 "help",    // #help
    "search/:query":        "search",  // #search/kiwis
    "search/:query/p:page": "search"   // #search/kiwis/p7
  },

  help: function() {
    ...
  },

  search: function(query, page) {
    ...
  }

});

routesrouter.routes
routes 將帶參數的 URLs 映射到路由實例的方法上(或只是直接的函數定義,如果你喜歡),這與 View(視圖)events hash(事件鍵值對) 非常類似。 路由可以包含參數, :param,它在斜線之間匹配 URL 組件。 路由也支持通配符, *splat,可以匹配多個 URL 組件。 路由的可選部分放在括號中(/:optional)

舉個例子,路由 "search/:query/p:page" 能匹配#search/obama/p2 , 這里傳入了 "obama""2" 到路由對應的動作中去了。

路由 "file/*path"可以匹配 #file/nested/folder/file.txt,這時傳入動作的參數為 "nested/folder/file.txt"

路由 "docs/:section(/:subsection)"可以匹配#docs/faq#docs/faq/installing,第一種情況,傳入 "faq" 到路由對應的動作中去, 第二種情況,傳入"faq""installing" 到路由對應的動作中去。

結尾的斜杠會被當作URL的一部分, 訪問時會被(正確地)當作一個獨立的路由。 docsdocs/將觸發不同的回調。 如果你不能避免產生這兩種類型的URLs時, 你可以定義一個"docs(/)"來匹配捕捉這兩種情況。

當訪問者點擊瀏覽器后退按鈕,或者輸入 URL ,如果匹配一個路由,此時會觸發一個基于動作名稱的 event, 其它對象可以監聽這個路由并接收到通知。 下面的示例中,用戶訪問 #help/uploading 將從路由中觸發 route:help 事件。

routes: {
  "help/:page":         "help",
  "download/*path":     "download",
  "folder/:name":       "openFolder",
  "folder/:name-:mode": "openFolder"
}
router.on("route:help", function(page) {
  ...
});

constructor / initializenew Router([options])
當創建一個新路由是,你可以直接傳入 routes 鍵值對象作為參數。 如果定義該參數, 它們將被傳入 initialize 構造函數中初始化。

routerouter.route(route, name, [callback])
為路由對象手動創建路由,route 參數可以是 routing string(路由字符串) 或 正則表達式。 每個捕捉到的被傳入的路由或正則表達式,都將作為參數傳入回調函數(callback)。 一旦路由匹配, name 參數會觸發 "route:name" 事件。如果callback參數省略 router[name]將被用來代替。 后來添加的路由可以覆蓋先前聲明的路由。

initialize: function(options) {

  // Matches #page/10, passing "10"
  this.route("page/:number", "page", function(number){ ... });

  // Matches /117-a/b/c/open, passing "117-a/b/c" to this.open
  this.route(/^(.*?)\/open$/, "open");

},

open: function(id) { ... }

navigaterouter.navigate(fragment, [options])
每當你達到你的應用的一個點時,你想保存為一個URL,  可以調用navigate以更新的URL。 如果您也想調用路由功能, 設置trigger選項設置為true。 無需在瀏覽器的歷史記錄創建條目來更新URL,  設置 replace選項設置為true

openPage: function(pageNumber) {
  this.document.pages.at(pageNumber).open();
  this.navigate("page/" + pageNumber);
}

# Or ...

app.navigate("help/troubleshooting", {trigger: true});

# Or ...

app.navigate("help/troubleshooting", {trigger: true, replace: true});

executerouter.execute(callback, args)
這種方法在路由內部被調用,  每當路由和其相應的callback匹配時被執行。 覆蓋它來執行自定義解析或包裝路由, 例如, 在傳遞他們給你的路由回調之前解析查詢字符串,像這樣:

var Router = Backbone.Router.extend({
  execute: function(callback, args) {
    args.push(parseQueryString(args.pop()));
    if (callback) callback.apply(this, args);
  }
});

Backbone.history

History 作為全局路由服務用于處理 hashchange 事件或 pushState,匹配適合的路由,并觸發回調函數。 我們不需要自己去做這些事情 — 如果使用帶有鍵值對的 路由,Backbone.history 會被自動創建。

Backbone 會自動判斷瀏覽器對 pushState 的支持,以做內部的選擇。 不支持 pushState 的瀏覽器將會繼續使用基于貓點的 URL 片段, 如果兼容 pushState 的瀏覽器訪問了某個 URL 貓點,將會被透明的轉換為真實的 URL。 注意使用真實的 URLs 需要 web 服務器支持直接渲染那些頁面,因此后端程序也需要做修改。 例如,如果有這樣一個路由 /document/100,如果瀏覽器直接訪問它, web 服務器必須能夠處理該頁面。 趨于對搜索引擎爬蟲的兼容,讓服務器完全為該頁面生成靜態 HTML 是非常好的做法 ... 但是如果要做的是一個 web 應用,只需要利用 Javascript 和 Backbone 視圖將服務器返回的 REST 數據渲染就很好了。

startBackbone.history.start([options])
當所有的 Routers 創建并設置完畢,調用 Backbone.history.start() 開始監控 hashchange 事件并分配路由。后續調用Backbone.history.start()會拋出一個錯誤, 并且Backbone.History.started是一個布爾值,指示是否已經被調用。

需要指出的是,如果想在應用中使用 HTML5 支持的 pushState,只需要這樣做:Backbone.history.start({pushState : true}) 。如果你想使用pushState的話, 對于那些本身不支持它的瀏覽器,需要用整頁刷新代替, 您可以添加{hashChange: false}到選項。

如果應用不是基于域名的根路徑 /,需要告訴 History 基于什么路徑: Backbone.history.start({pushState: true, root: "/public/search/"})

當執行后,如果某個路由成功匹配當前 URL,Backbone.history.start() 返回 true。 如果沒有定義的路由匹配當前 URL,返回 false

如果服務器已經渲染了整個頁面,但又不希望開始 History 時觸發初始路由,傳入 silent : true 即可。

因為在Internet Explorer中基于hash的歷史記錄依賴于<iframe>,因此需要確定DOM已準備就緒后再調用 start()

$(function(){
  new WorkspaceRouter();
  new HelpPaneRouter();
  Backbone.history.start({pushState: true});
});

Backbone.sync(同步)

Backbone.sync 是 Backbone 每次向服務器讀取或保存模型時都要調用執行的函數。 默認情況下,它使用 jQuery.ajax 方法發送 RESTful json 請求,并且返回一個 jqXHR。 如果想采用不同的持久化方案,比如 WebSockets, XML, 或 Local Storage,我們可以重載該函數。

Backbone.sync 的語法為 sync(method, model, [options])

  • method – CRUD 方法 ("create", "read", "update", or "delete")
  • model – 要被保存的模型(或要被讀取的集合)
  • options – 成功和失敗的回調函數,以及所有 jQuery 請求支持的選項

默認情況下,當 Backbone.sync 發送請求以保存模型時,其屬性會被序列化為 JSON,并以 application/json 的內容類型發送。 當接收到來自服務器的 JSON 響應后,對經過服務器改變的模型進行拆解,然后在客戶端更新。 當 "read" 請求從服務器端響應一個集合(Collection#fetch)時,便拆解模型屬性對象的數組。

當一個模型或集合開始 sync到服務器時,將觸發一個 "request" 事件。 如果請求成功完成,你會得到一個"sync"事件, 如果請求失敗,你會得到一個 "error"事件。

sync函數可重寫為全局性的Backbone.sync, 或在細粒度級別, 通過添加一個 sync函數 到Backbone集合或單個模型時。

默認 sync 映射 REST 風格的 CRUD 類似下面這樣:

  • create → POST   /collection
  • read → GET   /collection[/id]
  • update → PUT   /collection/id
  • patch → PATCH   /collection/id
  • delete → DELETE   /collection/id

舉個例子,一個Rail 4 處理程序響應一個來自Backbone"update"調用,可能是這樣的: (在真正的代碼中, 千萬不要盲目的使用update_attributes, ,你可以被改變的屬性始終是白名單。)

def update
  account = Account.find params[:id]
  account.update_attributes params.require(:account).permit(:name, :otherparam)
  render :json => account
end

一個技巧: 通過設置ActiveRecord::Base.include_root_in_json = false,在模型上禁用默認命名空間的to_json來整合 Rails 3.1之前的版本, 。

ajaxBackbone.ajax = function(request) { ... };
如果你想使用自定義的AJAX功能, 或者你的客戶端不支持的jQuery.ajax API,你需要調整的東西, 您可以通過設置Backbone.ajax這樣做。

emulateHTTPBackbone.emulateHTTP = true
如果你想在不支持Backbone的默認REST/ HTTP方式的Web服務器上工作, 您可以選擇開啟Backbone.emulateHTTP。 設置該選項將通過 POST 方法偽造 PUTPATCHDELETE 請求 用真實的方法設定X-HTTP-Method-Override頭信息。 如果支持emulateJSON,此時該請求會向服務器傳入名為 _method 的參數。

Backbone.emulateHTTP = true;

model.save();  // POST to "/collection/id", with "_method=PUT" + header.

emulateJSONBackbone.emulateJSON = true
如果你想在不支持發送 application/json 編碼請求的Web服務器上工作,設置Backbone.emulateJSON = true;將導致JSON根據模型參數進行序列化, 并通過application/x-www-form-urlencoded MIME類型來發送一個偽造HTML表單請求,

Backbone.View(視圖)

Backbone 視圖幾乎約定比他們的代碼多 — 他們并不限定你的HTML或CSS, 并可以配合使用任何JavaScript模板庫。 一般是組織您的接口轉換成邏輯視圖, 通過模型的支持, 模型變化時, 每一個都可以獨立地進行更新, 而不必重新繪制該頁面。我們再也不必鉆進 JSON 對象中,查找 DOM 元素,手動更新 HTML 了,通過綁定視圖的 render 函數到模型的 "change" 事件 — 模型數據會即時的顯示在 UI 中。

extendBackbone.View.extend(properties, [classProperties])
開始創建自定義的視圖類。 通常我們需要重載 render 函數,聲明 events, 以及通過 tagName, className, 或 id 為視圖指定根元素。

var DocumentRow = Backbone.View.extend({

  tagName: "li",

  className: "document-row",

  events: {
    "click .icon":          "open",
    "click .button.edit":   "openEditDialog",
    "click .button.delete": "destroy"
  },

  initialize: function() {
    this.listenTo(this.model, "change", this.render);
  },

  render: function() {
    ...
  }

});

直到運行時, 像tagName, id, className, el, 和 events這樣的屬性也可以被定義為一個函數,

constructor / initializenew View([options])
有幾個特殊的選項, 如果傳入,則直接注冊到視圖中去: model, collection, el, id, className, tagName, attributesevents。 如果視圖定義了一個initialize初始化函數, 首先創建視圖時,它會立刻被調用。 如果希望創建一個指向 DOM 中已存在的元素的視圖,傳入該元素作為選項:new View({el: existingElement})

var doc = documents.first();

new DocumentRow({
  model: doc,
  id: "document-row-" + doc.id
});

elview.el
所有的視圖都擁有一個 DOM 元素(el 屬性),即使該元素仍未插入頁面中去。 視圖可以在任何時候渲染,然后一次性插入 DOM 中去,這樣能盡量減少 reflows 和 repaints 從而獲得高性能的 UI 渲染。 this.el 可以從視圖的 tagName, className, idattributes 創建,如果都未指定,el 會是一個空 div

var ItemView = Backbone.View.extend({
  tagName: 'li'
});

var BodyView = Backbone.View.extend({
  el: 'body'
});

var item = new ItemView();
var body = new BodyView();

alert(item.el + ' ' + body.el);

$elview.$el
一個視圖元素的緩存jQuery對象。 一個簡單的引用,而不是重新包裝的DOM元素。

view.$el.show();

listView.$el.append(itemView.el);

setElementview.setElement(element)
如果你想應用一個Backbone視圖到不同的DOM元素, 使用setElement, 這也將創造緩存$el引用,視圖的委托事件從舊元素移動到新元素上。

attributesview.attributes
屬性的鍵值對, 將被設置為視圖el上的HTML DOM元素的屬性, 或者是返回這樣的鍵值對的一個函數。

$ (jQuery)view.$(selector)
如果頁面中引入了 jQuery,每個視圖都將擁有 $ 函數,可以在視圖元素查詢作用域內運行。 如果使用該作用域內的 jQuery 函數,就不需要從列表中指定的元素獲取模型的 ids 這種查詢了,我們可以更多的依賴 HTML class 屬性。 它等價于運行:view.$el.find(selector)

ui.Chapter = Backbone.View.extend({
  serialize : function() {
    return {
      title: this.$(".title").text(),
      start: this.$(".start-page").text(),
      end:   this.$(".end-page").text()
    };
  }
});

templateview.template([data])
雖然模板化的視圖 不是Backbone直接提供的一個功能, 它往往是一個在你視圖定義template函數很好的約定。 如此, 渲染你的視圖時, 您方便地訪問實例數據。 例如,使用Underscore的模板:

var LibraryView = Backbone.View.extend({
  template: _.template(...)
});

renderview.render()
render 默認實現是沒有操作的。 重載本函數可以實現從模型數據渲染視圖模板,并可用新的 HTML 更新 this.el。 推薦的做法是在 render 函數的末尾 return this 以開啟鏈式調用。

var Bookmark = Backbone.View.extend({
  template: _.template(...),
  render: function() {
    this.$el.html(this.template(this.model.attributes));
    return this;
  }
});

Backbone并不知道您首選HTML模板的方法。 render(渲染) 函數中可以采用拼接HTML字符串,, 或者使用document.createElement生成DOM樹。 但還是建議選擇一個好的 Javascript 模板引擎。 Mustache.js, Haml-js, 和 Eco 都是很好的選擇。 因為Underscore.js已經引入頁面了,如果你喜歡簡單的插入JavaScript的樣式模板。  _.template可以使用并是一個很好的選擇。

無論基于什么考慮,都永遠不要在 Javascript 中拼接 HTML 字符串。 在DocumentCloud中, 我們使用Jammit 來打包JavaScript模板,并存儲在/app/views中,作為我們主要的core.js包的一部分。

removeview.remove()
從 DOM 中移除一個視圖。同事調用stopListening來移除通過 listenTo綁定在視圖上的 所有事件。

delegateEventsdelegateEvents([events])
采用 jQuery 的on函數來為視圖內的 DOM 事件提供回調函數聲明。 如果未傳入 events 對象,使用 this.events 作為事件源。 事件對象的書寫格式為 {"event selector": "callback"}。 省略 selector 則事件被綁定到視圖的根元素(this.el)。 默認情況下,delegateEvents 會在視圖的構造函數內被調用,因此如果有 events 對象,所有的 DOM 事件已經被連接, 并且我們永遠不需要去手動調用本函數。

events 屬性也可以被定義成返回 events 對象的函數,這樣讓我們定義事件,以及實現事件的繼承變得更加方便。

視圖 render 期間使用 delegateEvents 相比用 jQuery 向子元素綁定事件有更多優點。 所有注冊的函數在傳遞給 jQuery 之前已被綁定到視圖上,因此當回調函數執行時, this 仍將指向視圖對象。 當 delegateEvents 再次運行,此時或許需要一個不同的 events 對象,所以所有回調函數將被移除,然后重新委托 — 這對模型不同行為也不同的視圖挺有用處。

搜索結果頁面顯示文檔的視圖看起來類似這樣:

var DocumentView = Backbone.View.extend({

  events: {
    "dblclick"                : "open",
    "click .icon.doc"         : "select",
    "contextmenu .icon.doc"   : "showMenu",
    "click .show_notes"       : "toggleNotes",
    "click .title .lock"      : "editAccessLevel",
    "mouseover .title .date"  : "showTooltip"
  },

  render: function() {
    this.$el.html(this.template(this.model.attributes));
    return this;
  },

  open: function() {
    window.open(this.model.get("viewer_url"));
  },

  select: function() {
    this.model.set({selected: true});
  },

  ...

});

undelegateEventsundelegateEvents()
刪除視圖所有委托事件。如果要從臨時的DOM中禁用或刪除視圖時,比較有用。

Utility(實用功能)

Backbone.noConflictvar backbone = Backbone.noConflict();
返回 Backbone 對象的原始值。 您可以使用Backbone.noConflict()的返回值以保持局部引用Backbone。 通常用于在第三方網站上引入了多個 Backbone 文件,避免沖突。

var localBackbone = Backbone.noConflict();
var model = localBackbone.Model.extend(...);

Backbone.$Backbone.$ = $;
如果頁面上有多個jQuery副本, 或者只是想告訴Backbone使用特定對象作為其DOM / Ajax庫, 那么這個屬性可以為您服務。  如果您正在使用CommonJS加載Backbone (例如,節點,組件,或browserify) 您必須手動設置該屬性。

var Backbone.$ = require('jquery');

F.A.Q.

Why use Backbone, not [other framework X]?
If your eye hasn't already been caught by the adaptability and elan on display in the above list of examples, we can get more specific: Backbone.js aims to provide the common foundation that data-rich web applications with ambitious interfaces require — while very deliberately avoiding painting you into a corner by making any decisions that you're better equipped to make yourself.

  • The focus is on supplying you with helpful methods to manipulate and query your data, not on HTML widgets or reinventing the JavaScript object model.
  • Backbone does not force you to use a single template engine. Views can bind to HTML constructed in your favorite way.
  • It's smaller. There are fewer kilobytes for your browser or phone to download, and less conceptual surface area. You can read and understand the source in an afternoon.
  • It doesn't depend on stuffing application logic into your HTML. There's no embedded JavaScript, template logic, or binding hookup code in data- or ng- attributes, and no need to invent your own HTML tags.
  • Synchronous events are used as the fundamental building block, not a difficult-to-reason-about run loop, or by constantly polling and traversing your data structures to hunt for changes. And if you want a specific event to be asynchronous and aggregated, no problem.
  • Backbone scales well, from embedded widgets to massive apps.
  • Backbone is a library, not a framework, and plays well with others. You can embed Backbone widgets in Dojo apps without trouble, or use Backbone models as the data backing for D3 visualizations (to pick two entirely random examples).
  • "Two-way data-binding" is avoided. While it certainly makes for a nifty demo, and works for the most basic CRUD, it doesn't tend to be terribly useful in your real-world app. Sometimes you want to update on every keypress, sometimes on blur, sometimes when the panel is closed, and sometimes when the "save" button is clicked. In almost all cases, simply serializing the form to JSON is faster and easier. All that aside, if your heart is set, go for it.
  • There's no built-in performance penalty for choosing to structure your code with Backbone. And if you do want to optimize further, thin models and templates with flexible granularity make it easy to squeeze every last drop of potential performance out of, say, IE8.

There's More Than One Way To Do It
It's common for folks just getting started to treat the examples listed on this page as some sort of gospel truth. In fact, Backbone.js is intended to be fairly agnostic about many common patterns in client-side code. For example...

References between Models and Views can be handled several ways. Some people like to have direct pointers, where views correspond 1:1 with models (model.view and view.model). Others prefer to have intermediate "controller" objects that orchestrate the creation and organization of views into a hierarchy. Others still prefer the evented approach, and always fire events instead of calling methods directly. All of these styles work well.

Batch operations on Models are common, but often best handled differently depending on your server-side setup. Some folks don't mind making individual Ajax requests. Others create explicit resources for RESTful batch operations: /notes/batch/destroy?ids=1,2,3,4. Others tunnel REST over JSON, with the creation of "changeset" requests:

  {
    "create":  [array of models to create]
    "update":  [array of models to update]
    "destroy": [array of model ids to destroy]
  }

Feel free to define your own events. Backbone.Events is designed so that you can mix it in to any JavaScript object or prototype. Since you can use any string as an event, it's often handy to bind and trigger your own custom events: model.on("selected:true") or model.on("editing")

Render the UI as you see fit. Backbone is agnostic as to whether you use Underscore templates, Mustache.js, direct DOM manipulation, server-side rendered snippets of HTML, or jQuery UI in your render function. Sometimes you'll create a view for each model ... sometimes you'll have a view that renders thousands of models at once, in a tight loop. Both can be appropriate in the same app, depending on the quantity of data involved, and the complexity of the UI.

Nested Models & Collections
It's common to nest collections inside of models with Backbone. For example, consider a Mailbox model that contains many Message models. One nice pattern for handling this is have a this.messages collection for each mailbox, enabling the lazy-loading of messages, when the mailbox is first opened ... perhaps with MessageList views listening for "add" and "remove" events.

var Mailbox = Backbone.Model.extend({

  initialize: function() {
    this.messages = new Messages;
    this.messages.url = '/mailbox/' + this.id + '/messages';
    this.messages.on("reset", this.updateCounts);
  },

  ...

});

var inbox = new Mailbox;

// And then, when the Inbox is opened:

inbox.messages.fetch({reset: true});

If you're looking for something more opinionated, there are a number of Backbone plugins that add sophisticated associations among models, available on the wiki.

Backbone doesn't include direct support for nested models and collections or "has many" associations because there are a number of good patterns for modeling structured data on the client side, and Backbone should provide the foundation for implementing any of them. You may want to…

  • Mirror an SQL database's structure, or the structure of a NoSQL database.
  • Use models with arrays of "foreign key" ids, and join to top level collections (a-la tables).
  • For associations that are numerous, use a range of ids instead of an explicit list.
  • Avoid ids, and use direct references, creating a partial object graph representing your data set.
  • Lazily load joined models from the server, or lazily deserialize nested models from JSON documents.

Loading Bootstrapped Models
When your app first loads, it's common to have a set of initial models that you know you're going to need, in order to render the page. Instead of firing an extra AJAX request to fetch them, a nicer pattern is to have their data already bootstrapped into the page. You can then use reset to populate your collections with the initial data. At DocumentCloud, in the ERB template for the workspace, we do something along these lines:

<script>
  var accounts = new Backbone.Collection;
  accounts.reset(<%= @accounts.to_json %>);
  var projects = new Backbone.Collection;
  projects.reset(<%= @projects.to_json(:collaborators => true) %>);
</script>

You have to escape </ within the JSON string, to prevent javascript injection attacks.

Extending Backbone
Many JavaScript libraries are meant to be insular and self-enclosed, where you interact with them by calling their public API, but never peek inside at the guts. Backbone.js is not that kind of library.

Because it serves as a foundation for your application, you're meant to extend and enhance it in the ways you see fit — the entire source code is annotated to make this easier for you. You'll find that there's very little there apart from core functions, and most of those can be overridden or augmented should you find the need. If you catch yourself adding methods to Backbone.Model.prototype, or creating your own base subclass, don't worry — that's how things are supposed to work.

How does Backbone relate to "traditional" MVC?
Different implementations of the Model-View-Controller pattern tend to disagree about the definition of a controller. If it helps any, in Backbone, the View class can also be thought of as a kind of controller, dispatching events that originate from the UI, with the HTML template serving as the true view. We call it a View because it represents a logical chunk of UI, responsible for the contents of a single DOM element.

Comparing the overall structure of Backbone to a server-side MVC framework like Rails, the pieces line up like so:

  • Backbone.Model – Like a Rails model minus the class methods. Wraps a row of data in business logic.
  • Backbone.Collection – A group of models on the client-side, with sorting/filtering/aggregation logic.
  • Backbone.Router – Rails routes.rb + Rails controller actions. Maps URLs to functions.
  • Backbone.View – A logical, re-usable piece of UI. Often, but not always, associated with a model.
  • Client-side Templates – Rails .html.erb views, rendering a chunk of HTML.

Binding "this"
Perhaps the single most common JavaScript "gotcha" is the fact that when you pass a function as a callback, its value for this is lost. When dealing with events and callbacks in Backbone, you'll often find it useful to rely on listenTo or the optional context argument that many of Underscore and Backbone's methods use to specify the this that will be used when the callback is later invoked. (See _.each, _.map, and object.on, to name a few). View events are automatically bound to the view's context for you. You may also find it helpful to use _.bind and _.bindAll from Underscore.js.

var MessageList = Backbone.View.extend({

  initialize: function() {
    var messages = this.collection;
    messages.on("reset", this.render, this);
    messages.on("add", this.addMessage, this);
    messages.on("remove", this.removeMessage, this);

    messsages.each(this.addMessage, this);
  }

});

// Later, in the app...

Inbox.messages.add(newMessage);

Working with Rails
Backbone.js was originally extracted from a Rails application; getting your client-side (Backbone) Models to sync correctly with your server-side (Rails) Models is painless, but there are still a few things to be aware of.

By default, Rails versions prior to 3.1 add an extra layer of wrapping around the JSON representation of models. You can disable this wrapping by setting:

ActiveRecord::Base.include_root_in_json = false

... in your configuration. Otherwise, override parse to pull model attributes out of the wrapper. Similarly, Backbone PUTs and POSTs direct JSON representations of models, where by default Rails expects namespaced attributes. You can have your controllers filter attributes directly from params, or you can override toJSON in Backbone to add the extra wrapping Rails expects.

Examples

The list of examples that follows, while long, is not exhaustive. If you've worked on an app that uses Backbone, please add it to the wiki page of Backbone apps.

Jér?me Gravel-Niquet has contributed a Todo List application that is bundled in the repository as Backbone example. If you're wondering where to get started with Backbone in general, take a moment to read through the annotated source. The app uses a LocalStorage adapter to transparently save all of your todos within your browser, instead of sending them to a server. Jér?me also has a version hosted at localtodos.com.

DocumentCloud

The DocumentCloud workspace is built on Backbone.js, with Documents, Projects, Notes, and Accounts all as Backbone models and collections. If you're interested in history — both Underscore.js and Backbone.js were originally extracted from the DocumentCloud codebase, and packaged into standalone JS libraries.

USA Today

USA Today takes advantage of the modularity of Backbone's data/model lifecycle — which makes it simple to create, inherit, isolate, and link application objects — to keep the codebase both manageable and efficient. The new website also makes heavy use of the Backbone Router to control the page for both pushState-capable and legacy browsers. Finally, the team took advantage of Backbone's Event module to create a PubSub API that allows third parties and analytics packages to hook into the heart of the app.

Rdio

New Rdio was developed from the ground up with a component based framework based on Backbone.js. Every component on the screen is dynamically loaded and rendered, with data provided by the Rdio API. When changes are pushed, every component can update itself without reloading the page or interrupting the user's music. All of this relies on Backbone's views and models, and all URL routing is handled by Backbone's Router. When data changes are signaled in realtime, Backbone's Events notify the interested components in the data changes. Backbone forms the core of the new, dynamic, realtime Rdio web and desktop applications.

Hulu

Hulu used Backbone.js to build its next generation online video experience. With Backbone as a foundation, the web interface was rewritten from scratch so that all page content can be loaded dynamically with smooth transitions as you navigate. Backbone makes it easy to move through the app quickly without the reloading of scripts and embedded videos, while also offering models and collections for additional data manipulation support.

Quartz

Quartz sees itself as a digitally native news outlet for the new global economy. Because Quartz believes in the future of open, cross-platform web applications, they selected Backbone and Underscore to fetch, sort, store, and display content from a custom WordPress API. Although qz.com uses responsive design for phone, tablet, and desktop browsers, it also takes advantage of Backbone events and views to render device-specific templates in some cases.

Earth

Earth.nullschool.net displays real-time weather conditions on an interactive animated globe, and Backbone provides the foundation upon which all of the site's components are built. Despite the presence of several other javascript libraries, Backbone's non-opinionated design made it effortless to mix-in the Events functionality used for distributing state changes throughout the page. When the decision was made to switch to Backbone, large blocks of custom logic simply disappeared.

Vox

Vox Media, the publisher of SB Nation, The Verge, Polygon, Eater, Racked, Curbed, and Vox.com, uses Backbone throughout Chorus, its home-grown publishing platform. Backbone powers the liveblogging platform and commenting system used across all Vox Media properties; Coverage, an internal editorial coordination tool; SB Nation Live, a live event coverage and chat tool; and Vox Cards, Vox.com's highlighter-and-index-card inspired app for providing context about the news.

Gawker Media

Kinja is Gawker Media's publishing platform designed to create great stories by breaking down the lines between the traditional roles of content creators and consumers. Everyone — editors, readers, marketers — have access to the same tools to engage in passionate discussion and pursue the truth of the story. Sharing, recommending, and following within the Kinja ecosystem allows for improved information discovery across all the sites.

Kinja is the platform behind Gawker, Gizmodo, Lifehacker, io9 and other Gawker Media blogs. Backbone.js underlies the front-end application code that powers everything from user authentication to post authoring, commenting, and even serving ads. The JavaScript stack includes Underscore.js and jQuery, with some plugins, all loaded with RequireJS. Closure templates are shared between the Play! Framework based Scala application and Backbone views, and the responsive layout is done with the Foundation framework using SASS.

Flow

MetaLab used Backbone.js to create Flow, a task management app for teams. The workspace relies on Backbone.js to construct task views, activities, accounts, folders, projects, and tags. You can see the internals under window.Flow.

Gilt Groupe

Gilt Groupe uses Backbone.js to build multiple applications across their family of sites. Gilt's mobile website uses Backbone and Zepto.js to create a blazing-fast shopping experience for users on-the-go, while Gilt Live combines Backbone with WebSockets to display the items that customers are buying in real-time. Gilt's search functionality also uses Backbone to filter and sort products efficiently by moving those actions to the client-side.

Enigma

Enigma is a portal amassing the largest collection of public data produced by governments, universities, companies, and organizations. Enigma uses Backbone Models and Collections to represent complex data structures; and Backbone's Router gives Enigma users unique URLs for application states, allowing them to navigate quickly through the site while maintaining the ability to bookmark pages and navigate forward and backward through their session.

NewsBlur

NewsBlur is an RSS feed reader and social news network with a fast and responsive UI that feels like a native desktop app. Backbone.js was selected for a major rewrite and transition from spaghetti code because of its powerful yet simple feature set, easy integration, and large community. If you want to poke around under the hood, NewsBlur is also entirely open-source.

WordPress.com

WordPress.com is the software-as-a-service version of WordPress. It uses Backbone.js Models, Collections, and Views in its Notifications system. Backbone.js was selected because it was easy to fit into the structure of the application, not the other way around. Automattic (the company behind WordPress.com) is integrating Backbone.js into the Stats tab and other features throughout the homepage.

Foursquare

Foursquare is a fun little startup that helps you meet up with friends, discover new places, and save money. Backbone Models are heavily used in the core JavaScript API layer and Views power many popular features like the homepage map and lists.

Bitbucket

Bitbucket is a free source code hosting service for Git and Mercurial. Through its models and collections, Backbone.js has proved valuable in supporting Bitbucket's REST API, as well as newer components such as in-line code comments and approvals for pull requests. Mustache templates provide server and client-side rendering, while a custom Google Closure inspired life-cycle for widgets allows Bitbucket to decorate existing DOM trees and insert new ones.

Disqus

Disqus chose Backbone.js to power the latest version of their commenting widget. Backbone’s small footprint and easy extensibility made it the right choice for Disqus’ distributed web application, which is hosted entirely inside an iframe and served on thousands of large web properties, including IGN, Wired, CNN, MLB, and more.

Delicious

Delicious is a social bookmarking platform making it easy to save, sort, and store bookmarks from across the web. Delicious uses Chaplin.js, Backbone.js and AppCache to build a full-featured MVC web app. The use of Backbone helped the website and mobile apps share a single API service, and the reuse of the model tier made it significantly easier to share code during the recent Delicious redesign.

Khan Academy

Khan Academy is on a mission to provide a free world-class education to anyone anywhere. With thousands of videos, hundreds of JavaScript-driven exercises, and big plans for the future, Khan Academy uses Backbone to keep frontend code modular and organized. User profiles and goal setting are implemented with Backbone, jQuery and Handlebars, and most new feature work is being pushed to the client side, greatly increasing the quality of the API.

IRCCloud

IRCCloud is an always-connected IRC client that you use in your browser — often leaving it open all day in a tab. The sleek web interface communicates with an Erlang backend via websockets and the IRCCloud API. It makes heavy use of Backbone.js events, models, views and routing to keep your IRC conversations flowing in real time.

Pitchfork

Pitchfork uses Backbone.js to power its site-wide audio player, Pitchfork.tv, location routing, a write-thru page fragment cache, and more. Backbone.js (and Underscore.js) helps the team create clean and modular components, move very quickly, and focus on the site, not the spaghetti.

Spin

Spin pulls in the latest news stories from their internal API onto their site using Backbone models and collections, and a custom sync method. Because the music should never stop playing, even as you click through to different "pages", Spin uses a Backbone router for navigation within the site.

ZocDoc

ZocDoc helps patients find local, in-network doctors and dentists, see their real-time availability, and instantly book appointments. On the public side, the webapp uses Backbone.js to handle client-side state and rendering in search pages and doctor profiles. In addition, the new version of the doctor-facing part of the website is a large single-page application that benefits from Backbone's structure and modularity. ZocDoc's Backbone classes are tested with Jasmine, and delivered to the end user with Cassette.

Walmart Mobile

Walmart used Backbone.js to create the new version of their mobile web application and created two new frameworks in the process. Thorax provides mixins, inheritable events, as well as model and collection view bindings that integrate directly with Handlebars templates. Lumbar allows the application to be split into modules which can be loaded on demand, and creates platform specific builds for the portions of the web application that are embedded in Walmart's native Android and iOS applications.

Groupon Now!

Groupon Now! helps you find local deals that you can buy and use right now. When first developing the product, the team decided it would be AJAX heavy with smooth transitions between sections instead of full refreshes, but still needed to be fully linkable and shareable. Despite never having used Backbone before, the learning curve was incredibly quick — a prototype was hacked out in an afternoon, and the team was able to ship the product in two weeks. Because the source is minimal and understandable, it was easy to add several Backbone extensions for Groupon Now!: changing the router to handle URLs with querystring parameters, and adding a simple in-memory store for caching repeated requests for the same data.

Basecamp

37Signals chose Backbone.js to create the calendar feature of its popular project management software Basecamp. The Basecamp Calendar uses Backbone.js models and views in conjunction with the Eco templating system to present a polished, highly interactive group scheduling interface.

Slavery Footprint

Slavery Footprint allows consumers to visualize how their consumption habits are connected to modern-day slavery and provides them with an opportunity to have a deeper conversation with the companies that manufacture the goods they purchased. Based in Oakland, California, the Slavery Footprint team works to engage individuals, groups, and businesses to build awareness for and create deployable action against forced labor, human trafficking, and modern-day slavery through online tools, as well as off-line community education and mobilization programs.

Stripe

Stripe provides an API for accepting credit cards on the web. Stripe's management interface was recently rewritten from scratch in CoffeeScript using Backbone.js as the primary framework, Eco for templates, Sass for stylesheets, and Stitch to package everything together as CommonJS modules. The new app uses Stripe's API directly for the majority of its actions; Backbone.js models made it simple to map client-side models to their corresponding RESTful resources.

Airbnb

Airbnb uses Backbone in many of its products. It started with Airbnb Mobile Web (built in six weeks by a team of three) and has since grown to Wish Lists, Match, Search, Communities, Payments, and Internal Tools.

SoundCloud Mobile

SoundCloud is the leading sound sharing platform on the internet, and Backbone.js provides the foundation for SoundCloud Mobile. The project uses the public SoundCloud API as a data source (channeled through a nginx proxy), jQuery templates for the rendering, Qunit and PhantomJS for the testing suite. The JS code, templates and CSS are built for the production deployment with various Node.js tools like ready.js, Jake, jsdom. The Backbone.History was modified to support the HTML5 history.pushState. Backbone.sync was extended with an additional SessionStorage based cache layer.

Art.sy

Art.sy is a place to discover art you'll love. Art.sy is built on Rails, using Grape to serve a robust JSON API. The main site is a single page app written in CoffeeScript and uses Backbone to provide structure around this API. An admin panel and partner CMS have also been extracted into their own API-consuming Backbone projects.

Pandora

When Pandora redesigned their site in HTML5, they chose Backbone.js to help manage the user interface and interactions. For example, there's a model that represents the "currently playing track", and multiple views that automatically update when the current track changes. The station list is a collection, so that when stations are added or changed, the UI stays up to date.

Inkling

Inkling is a cross-platform way to publish interactive learning content. Inkling for Web uses Backbone.js to make hundreds of complex books — from student textbooks to travel guides and programming manuals — engaging and accessible on the web. Inkling supports WebGL-enabled 3D graphics, interactive assessments, social sharing, and a system for running practice code right in the book, all within a single page Backbone-driven app. Early on, the team decided to keep the site lightweight by using only Backbone.js and raw JavaScript. The result? Complete source code weighing in at a mere 350kb with feature-parity across the iPad, iPhone and web clients. Give it a try with this excerpt from JavaScript: The Definitive Guide.

Code School

Code School courses teach people about various programming topics like CoffeeScript, CSS, Ruby on Rails, and more. The new Code School course challenge page is built from the ground up on Backbone.js, using everything it has to offer: the router, collections, models, and complex event handling. Before, the page was a mess of jQuery DOM manipulation and manual Ajax calls. Backbone.js helped introduce a new way to think about developing an organized front-end application in JavaScript.

CloudApp

CloudApp is simple file and link sharing for the Mac. Backbone.js powers the web tools which consume the documented API to manage Drops. Data is either pulled manually or pushed by Pusher and fed to Mustache templates for rendering. Check out the annotated source code to see the magic.

SeatGeek

SeatGeek's stadium ticket maps were originally developed with Prototype.js. Moving to Backbone.js and jQuery helped organize a lot of the UI code, and the increased structure has made adding features a lot easier. SeatGeek is also in the process of building a mobile interface that will be Backbone.js from top to bottom.

Easel

Easel is an in-browser, high fidelity web design tool that integrates with your design and development process. The Easel team uses CoffeeScript, Underscore.js and Backbone.js for their rich visual editor as well as other management functions throughout the site. The structure of Backbone allowed the team to break the complex problem of building a visual editor into manageable components and still move quickly.

Jolicloud

Jolicloud is an open and independent platform and operating system that provides music playback, video streaming, photo browsing and document editing — transforming low cost computers into beautiful cloud devices. The new Jolicloud HTML5 app was built from the ground up using Backbone and talks to the Jolicloud Platform, which is based on Node.js. Jolicloud works offline using the HTML5 AppCache, extends Backbone.sync to store data in IndexedDB or localStorage, and communicates with the Joli OS via WebSockets.

Salon.io

Salon.io provides a space where photographers, artists and designers freely arrange their visual art on virtual walls. Salon.io runs on Rails, but does not use much of the traditional stack, as the entire frontend is designed as a single page web app, using Backbone.js, Brunch and CoffeeScript.

TileMill

Our fellow Knight Foundation News Challenge winners, MapBox, created an open-source map design studio with Backbone.js: TileMill. TileMill lets you manage map layers based on shapefiles and rasters, and edit their appearance directly in the browser with the Carto styling language. Note that the gorgeous MapBox homepage is also a Backbone.js app.

Blossom

Blossom is a lightweight project management tool for lean teams. Backbone.js is heavily used in combination with CoffeeScript to provide a smooth interaction experience. The app is packaged with Brunch. The RESTful backend is built with Flask on Google App Engine.

Trello

Trello is a collaboration tool that organizes your projects into boards. A Trello board holds many lists of cards, which can contain checklists, files and conversations, and may be voted on and organized with labels. Updates on the board happen in real time. The site was built ground up using Backbone.js for all the models, views, and routes.

Tzigla

Cristi Balan and Irina Dumitrascu created Tzigla, a collaborative drawing application where artists make tiles that connect to each other to create surreal drawings. Backbone models help organize the code, routers provide bookmarkable deep links, and the views are rendered with haml.js and Zepto. Tzigla is written in Ruby (Rails) on the backend, and CoffeeScript on the frontend, with Jammit prepackaging the static assets.

Change Log

1.1.2Feb. 20, 2014DiffDocs
  • Backbone no longer tries to require jQuery in Node/CommonJS environments, for better compatibility with folks using Browserify. If you'd like to have Backbone use jQuery from Node, assign it like so: Backbone.$ = require('jquery');
  • Bugfix for route parameters with newlines in them.
1.1.1Feb. 13, 2014DiffDocs
  • Backbone now registers itself for AMD (Require.js), Bower and Component, as well as being a CommonJS module and a regular (Java)Script. Whew.
  • Added an execute hook to the Router, which allows you to hook in and custom-parse route arguments, like query strings, for example.
  • Performance fine-tuning for Backbone Events.
  • Better matching for Unicode in routes, in old browsers.
  • Backbone Routers now handle query params in route fragments, passing them into the handler as the last argument. Routes specified as strings should no longer include the query string ('foo?:query' should be 'foo').
1.1.0Oct. 10, 2013DiffDocs
  • Made the return values of Collection's set, add, remove, and reset more useful. Instead of returning this, they now return the changed (added, removed or updated) model or list of models.
  • Backbone Views no longer automatically attach options passed to the constructor as this.options and Backbone Models no longer attach url and urlRoot options, but you can do it yourself if you prefer.
  • All "invalid" events now pass consistent arguments. First the model in question, then the error object, then options.
  • You are no longer permitted to change the id of your model during parse. Use idAttribute instead.
  • On the other hand, parse is now an excellent place to extract and vivify incoming nested JSON into associated submodels.
  • Many tweaks, optimizations and bugfixes relating to Backbone 1.0, including URL overrides, mutation of options, bulk ordering, trailing slashes, edge-case listener leaks, nested model parsing...
1.0.0March 20, 2013DiffDocs
  • Renamed Collection's "update" to set, for parallelism with the similar model.set(), and contrast with reset. It's now the default updating mechanism after a fetch. If you'd like to continue using "reset", pass {reset: true}.
  • Your route handlers will now receive their URL parameters pre-decoded.
  • Added listenToOnce as the analogue of once.
  • Added the findWhere method to Collections, similar to where.
  • Added the keys, values, pairs, invert, pick, and omit Underscore.js methods to Backbone Models.
  • The routes in a Router's route map may now be function literals, instead of references to methods, if you like.
  • url and urlRoot properties may now be passed as options when instantiating a new Model.
0.9.10Jan. 15, 2013DiffDocs
  • A "route" event is triggered on the router in addition to being fired on Backbone.history.
  • Model validation is now only enforced by default in Model#save and no longer enforced by default upon construction or in Model#set, unless the {validate:true} option is passed.
  • View#make has been removed. You'll need to use $ directly to construct DOM elements now.
  • Passing {silent:true} on change will no longer delay individual "change:attr" events, instead they are silenced entirely.
  • The Model#change method has been removed, as delayed attribute changes are no longer available.
  • Bug fix on change where attribute comparison uses !== instead of _.isEqual.
  • Bug fix where an empty response from the server on save would not call the success function.
  • parse now receives options as its second argument.
  • Model validation now fires invalid event instead of error.
0.9.9Dec. 13, 2012DiffDocs
  • Added listenTo and stopListening to Events. They can be used as inversion-of-control flavors of on and off, for convenient unbinding of all events an object is currently listening to. view.remove() automatically calls view.stopListening().
  • When using add on a collection, passing {merge: true} will now cause duplicate models to have their attributes merged in to the existing models, instead of being ignored.
  • Added update (which is also available as an option to fetch) for "smart" updating of sets of models.
  • HTTP PATCH support in save by passing {patch: true}.
  • The Backbone object now extends Events so that you can use it as a global event bus, if you like.
  • Added a "request" event to Backbone.sync, which triggers whenever a request begins to be made to the server. The natural complement to the "sync" event.
  • Router URLs now support optional parts via parentheses, without having to use a regex.
  • Backbone events now supports once, similar to Node's once, or jQuery's one.
  • Backbone events now support jQuery-style event maps obj.on({click: action}).
  • While listening to a reset event, the list of previous models is now available in options.previousModels, for convenience.
  • Validation now occurs even during "silent" changes. This change means that the isValid method has been removed. Failed validations also trigger an error, even if an error callback is specified in the options.
  • Consolidated "sync" and "error" events within Backbone.sync. They are now triggered regardless of the existence of success or error callbacks.
  • For mixed-mode APIs, Backbone.sync now accepts emulateHTTP and emulateJSON as inline options.
  • Collections now also proxy Underscore method name aliases (collect, inject, foldl, foldr, head, tail, take, and so on...)
  • Removed getByCid from Collections. collection.get now supports lookup by both id and cid.
  • After fetching a model or a collection, all defined parse functions will now be run. So fetching a collection and getting back new models could cause both the collection to parse the list, and then each model to be parsed in turn, if you have both functions defined.
  • Bugfix for normalizing leading and trailing slashes in the Router definitions. Their presence (or absence) should not affect behavior.
  • When declaring a View, options, el, tagName, id and className may now be defined as functions, if you want their values to be determined at runtime.
  • Added a Backbone.ajax hook for more convenient overriding of the default use of $.ajax. If AJAX is too passé, set it to your preferred method for server communication.
  • Collection#sort now triggers a sort event, instead of a reset event.
  • Calling destroy on a Model will now return false if the model isNew.
  • To set what library Backbone uses for DOM manipulation and Ajax calls, use Backbone.$ = ... instead of setDomLibrary.
  • Removed the Backbone.wrapError helper method. Overriding sync should work better for those particular use cases.
  • To improve the performance of add, options.index will no longer be set in the `add` event callback. collection.indexOf(model) can be used to retrieve the index of a model as necessary.
  • For semantic and cross browser reasons, routes will now ignore search parameters. Routes like search?query=…&page=3 should become search/…/3.
  • Model#set no longer accepts another model as an argument. This leads to subtle problems and is easily replaced with model.set(other.attributes).
0.9.2March 21, 2012DiffDocs
  • Instead of throwing an error when adding duplicate models to a collection, Backbone will now silently skip them instead.
  • Added push, pop, unshift, and shift to collections.
  • A model's changed hash is now exposed for easy reading of the changed attribute delta, since the model's last "change" event.
  • Added where to collections for simple filtering.
  • You can now use a single off call to remove all callbacks bound to a specific object.
  • Bug fixes for nested individual change events, some of which may be "silent".
  • Bug fixes for URL encoding in location.hash fragments.
  • Bug fix for client-side validation in advance of a save call with {wait: true}.
  • Updated / refreshed the example Todo List app.
0.9.1Feb. 2, 2012DiffDocs
  • Reverted to 0.5.3-esque behavior for validating models. Silent changes no longer trigger validation (making it easier to work with forms). Added an isValid function that you can use to check if a model is currently in a valid state.
  • If you have multiple versions of jQuery on the page, you can now tell Backbone which one to use with Backbone.setDomLibrary.
  • Fixes regressions in 0.9.0 for routing with "root", saving with both "wait" and "validate", and the order of nested "change" events.
0.9.0Jan. 30, 2012DiffDocs
  • Creating and destroying models with create and destroy are now optimistic by default. Pass {wait: true} as an option if you'd like them to wait for a successful server response to proceed.
  • Two new properties on views: $el — a cached jQuery (or Zepto) reference to the view's element, and setElement, which should be used instead of manually setting a view's el. It will both set view.el and view.$el correctly, as well as re-delegating events on the new DOM element.
  • You can now bind and trigger multiple spaced-delimited events at once. For example: model.on("change:name change:age", ...)
  • When you don't know the key in advance, you may now call model.set(key, value) as well as save.
  • Multiple models with the same id are no longer allowed in a single collection.
  • Added a "sync" event, which triggers whenever a model's state has been successfully synced with the server (create, save, destroy).
  • bind and unbind have been renamed to on and off for clarity, following jQuery's lead. The old names are also still supported.
  • A Backbone collection's comparator function may now behave either like a sortBy (pass a function that takes a single argument), or like a sort (pass a comparator function that expects two arguments). The comparator function is also now bound by default to the collection — so you can refer to this within it.
  • A view's events hash may now also contain direct function values as well as the string names of existing view methods.
  • Validation has gotten an overhaul — a model's validate function will now be run even for silent changes, and you can no longer create a model in an initially invalid state.
  • Added shuffle and initial to collections, proxied from Underscore.
  • Model#urlRoot may now be defined as a function as well as a value.
  • View#attributes may now be defined as a function as well as a value.
  • Calling fetch on a collection will now cause all fetched JSON to be run through the collection's model's parse function, if one is defined.
  • You may now tell a router to navigate(fragment, {replace: true}), which will either use history.replaceState or location.hash.replace, in order to change the URL without adding a history entry.
  • Within a collection's add and remove events, the index of the model being added or removed is now available as options.index.
  • Added an undelegateEvents to views, allowing you to manually remove all configured event delegations.
  • Although you shouldn't be writing your routes with them in any case — leading slashes (/) are now stripped from routes.
  • Calling clone on a model now only passes the attributes for duplication, not a reference to the model itself.
  • Calling clear on a model now removes the id attribute.

0.5.3August 9, 2011DiffDocs
A View's events property may now be defined as a function, as well as an object literal, making it easier to programmatically define and inherit events. groupBy is now proxied from Underscore as a method on Collections. If the server has already rendered everything on page load, pass Backbone.history.start({silent: true}) to prevent the initial route from triggering. Bugfix for pushState with encoded URLs.

0.5.2July 26, 2011DiffDocs
The bind function, can now take an optional third argument, to specify the this of the callback function. Multiple models with the same id are now allowed in a collection. Fixed a bug where calling .fetch(jQueryOptions) could cause an incorrect URL to be serialized. Fixed a brief extra route fire before redirect, when degrading from pushState.

0.5.1July 5, 2011DiffDocs
Cleanups from the 0.5.0 release, to wit: improved transparent upgrades from hash-based URLs to pushState, and vice-versa. Fixed inconsistency with non-modified attributes being passed to Model#initialize. Reverted a 0.5.0 change that would strip leading hashbangs from routes. Added contains as an alias for includes.

0.5.0July 1, 2011DiffDocs
A large number of tiny tweaks and micro bugfixes, best viewed by looking at the commit diff. HTML5 pushState support, enabled by opting-in with: Backbone.history.start({pushState: true}). Controller was renamed to Router, for clarity. Collection#refresh was renamed to Collection#reset to emphasize its ability to both reset the collection with new models, as well as empty out the collection when used with no parameters. saveLocation was replaced with navigate. RESTful persistence methods (save, fetch, etc.) now return the jQuery deferred object for further success/error chaining and general convenience. Improved XSS escaping for Model#escape. Added a urlRoot option to allow specifying RESTful urls without the use of a collection. An error is thrown if Backbone.history.start is called multiple times. Collection#create now validates before initializing the new model. view.el can now be a jQuery string lookup. Backbone Views can now also take an attributes parameter. Model#defaults can now be a function as well as a literal attributes object.

0.3.3Dec 1, 2010DiffDocs
Backbone.js now supports Zepto, alongside jQuery, as a framework for DOM manipulation and Ajax support. Implemented Model#escape, to efficiently handle attributes intended for HTML interpolation. When trying to persist a model, failed requests will now trigger an "error" event. The ubiquitous options argument is now passed as the final argument to all "change" events.

0.3.2Nov 23, 2010DiffDocs
Bugfix for IE7 + iframe-based "hashchange" events. sync may now be overridden on a per-model, or per-collection basis. Fixed recursion error when calling save with no changed attributes, within a "change" event.

0.3.1Nov 15, 2010DiffDocs
All "add" and "remove" events are now sent through the model, so that views can listen for them without having to know about the collection. Added a remove method to Backbone.View. toJSON is no longer called at all for 'read' and 'delete' requests. Backbone routes are now able to load empty URL fragments.

0.3.0Nov 9, 2010DiffDocs
Backbone now has Controllers and History, for doing client-side routing based on URL fragments. Added emulateHTTP to provide support for legacy servers that don't do PUT and DELETE. Added emulateJSON for servers that can't accept application/json encoded requests. Added Model#clear, which removes all attributes from a model. All Backbone classes may now be seamlessly inherited by CoffeeScript classes.

0.2.0Oct 25, 2010DiffDocs
Instead of requiring server responses to be namespaced under a model key, now you can define your own parse method to convert responses into attributes for Models and Collections. The old handleEvents function is now named delegateEvents, and is automatically called as part of the View's constructor. Added a toJSON function to Collections. Added Underscore's chain to Collections.

0.1.2Oct 19, 2010DiffDocs
Added a Model#fetch method for refreshing the attributes of single model from the server. An error callback may now be passed to set and save as an option, which will be invoked if validation fails, overriding the "error" event. You can now tell backbone to use the _method hack instead of HTTP methods by setting Backbone.emulateHTTP = true. Existing Model and Collection data is no longer sent up unnecessarily with GET and DELETE requests. Added a rake lint task. Backbone is now published as an NPM module.

0.1.1Oct 14, 2010DiffDocs
Added a convention for initialize functions to be called upon instance construction, if defined. Documentation tweaks.

0.1.0Oct 13, 2010Docs
Initial Backbone release.


A DocumentCloud Project

股票配资平台l选一直牛