Backbone.js 透過提供具備鍵值繫結和自訂事件的模型、具備豐富列舉函式 API 的集合、具備宣告式事件處理的檢視,並透過 RESTful JSON 介面將其全部連接到現有的 API,為 Web 應用程式提供結構。
此專案已託管在 GitHub,且附註原始碼和線上測試套件、範例應用程式、教學清單和使用 Backbone 的眾多實際專案清單皆可使用。Backbone 可在MIT 軟體授權下使用。
您可以在GitHub 議題頁面回報錯誤並討論功能,或將頁面新增至Wiki。
Backbone 是DocumentCloud的開源元件。
開發版本 (1.6.0) | 72kb,完整原始碼,大量註解 |
正式版本 (1.6.0) |
7.9kb,已壓縮並 gzip (原始碼對應表) |
Edge 版本 (master) | 未發布,請自行承擔風險使用 |
Backbone 唯一硬性依賴的套件是 Underscore.js ( >= 1.8.3)。若要使用 Backbone.View 進行 RESTful 持久化和 DOM 操作,請包含 jQuery ( >= 1.11.0)。(模仿 Underscore 和 jQuery API 的套件,例如 Lodash 和 Zepto,通常也可以使用,但相容性程度不一。)
在開發包含大量 JavaScript 的 Web 應用程式時,首先要學到的事情之一就是停止將資料繫結到 DOM。很容易就能建立出最後變成一堆混亂的 jQuery 選擇器和回呼的 JavaScript 應用程式,它們都瘋狂地試圖在 HTML UI、JavaScript 邏輯和伺服器上的資料庫之間保持資料同步。對於豐富的用戶端應用程式,通常採用更結構化的方式會很有幫助。
使用 Backbone,您可以將資料表示為 模型,這些模型可以建立、驗證、銷毀並儲存到伺服器。每當 UI 動作導致模型的屬性變更時,模型就會觸發一個「變更」事件;顯示模型狀態的所有 檢視 都會收到變更通知,因此它們可以適當地回應,並使用新的資訊重新呈現自己。在完成的 Backbone 應用程式中,您不必撰寫會搜尋 DOM 以找出具有特定id的元素,並手動更新 HTML 的黏合程式碼 — 當模型變更時,檢視會自動更新自己。
在哲學上,Backbone 嘗試找出資料結構化(模型和集合)和使用者介面(檢視和 URL)基元中,在使用 JavaScript 建立 Web 應用程式時通常有用的最小集合。在一個由決定一切的架構主導的生態系統中,許多函式庫要求您的網站重新組織以符合它們的外觀、感覺和預設行為 — Backbone 應該持續成為一個讓您自由設計 Web 應用程式完整體驗的工具。
如果您是新手,還不確定 Backbone 的用途,請先瀏覽 以 Backbone 為基礎的專案清單。
此文件中的許多程式碼範例都是可執行的,因為此頁面已包含 Backbone。按一下播放按鈕來執行這些範例。
Backbone 能幫你處理的最重要的一件事,就是將你的商業邏輯與使用者介面分開。當兩者糾纏在一起時,變更會很困難;當邏輯不依賴於使用者介面時,你的介面會變得更容易使用。
模型管理資料屬性的內部表格,並在任何資料修改時觸發 "變更" 事件。模型會處理與持久層同步資料,通常是具有後端資料庫的 REST API。將你的模型設計為包含所有有助於處理其特定資料片段的函式的原子可重複使用物件。模型應該能夠在你的應用程式中傳遞,並在需要資料片段的任何地方使用。
檢視是使用者介面的原子片段。它通常會呈現來自特定模型或多個模型的資料,但檢視也可以是獨立的無資料使用者介面片段。模型通常不會察覺檢視。相反地,檢視會偵聽模型 "變更" 事件,並適當地反應或重新呈現它們。
集合可協助你處理相關模型群組,處理載入和儲存新的模型至伺服器,並提供針對模型清單執行聚合或運算的輔助函式。除了它們自己的事件之外,集合還會代理傳遞它們內部模型發生的所有事件,讓你可以在一個地方偵聽可能發生在集合中任何模型的任何變更。
Backbone 已預先設定為與 RESTful API 同步。只要使用 url 建立新的集合,即可使用資源端點
var Books = Backbone.Collection.extend({ url: '/books' });
集合和模型元件共同使用下列方法,形成 REST 資源的直接對應
GET /books/ .... collection.fetch(); POST /books/ .... collection.create(); GET /books/1 ... model.fetch(); PUT /books/1 ... model.save(); DEL /books/1 ... model.destroy();
從 API 擷取原始 JSON 資料時,集合會自動使用格式化為陣列的資料填入資料,而模型會自動使用格式化為物件的資料填入資料
[{"id": 1}] ..... populates a Collection with one model. {"id": 1} ....... populates a Model with one attribute.
但是,遇到以不同於 Backbone 預期的格式傳回資料的 API 非常常見。例如,考慮從將實際資料陣列包覆在元資料中的 API 擷取集合
{ "page": 1, "limit": 10, "total": 2, "books": [ {"id": 1, "title": "Pride and Prejudice"}, {"id": 4, "title": "The Great Gatsby"} ] }
在上述範例資料中,Collection 應使用 "books" 陣列而不是根物件結構來填充。這個差異可以使用 parse 方法輕鬆調和,該方法會傳回(或轉換)API 資料的所需部分
var Books = Backbone.Collection.extend({ url: '/books', parse: function(data) { return data.books; } });
每個檢視管理其自己的 DOM 元素中的呈現和使用者互動。如果您嚴格不允許檢視超出其自身範圍,這有助於保持介面彈性,允許檢視在任何需要的地方獨立呈現。
Backbone 對於用於將檢視物件及其子檢視呈現到 UI 的程序保持中立:您定義模型如何轉換為 HTML(或 SVG、或畫布,或更奇特的東西)。它可以像簡單的 Underscore 範本 一樣平淡無奇,也可以像 React 虛擬 DOM 一樣花俏。可以在 Backbone 入門 中找到一些用於呈現檢視的基本方法。
在豐富的網路應用程式中,我們仍希望提供可連結、可書籤和可分享的 URL,以連結到應用程式內有意義的位置。使用Router 來更新瀏覽器 URL,每當使用者到達應用程式中他們可能想要書籤或分享的新「位置」時。相反地,Router 會偵測 URL 的變更(例如按下「返回」按鈕),並可以準確地告訴您的應用程式您現在在哪裡。
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])
別名:繫結
將callback 函式繫結到物件。每當event 被觸發時,將會呼叫 callback。如果您在頁面上有大量的不同事件,慣例是使用冒號為它們命名空間:"poll:start" 或 "change:selection"。事件字串也可以是數個事件的空白分隔清單...
book.on("change:title change:author", ...);
繫結到特殊 "all" 事件的 callback 將在發生任何事件時觸發,並將事件名稱作為第一個引數傳遞。例如,要將所有事件從一個物件代理到另一個物件
proxy.on("all", function(eventName) { object.trigger(eventName); });
所有 Backbone 事件方法也支援事件對應語法,作為位置參數的替代方案
book.on({ "change:author": authorPane.update, "change:title change:subtitle": titleView.update, "destroy": bookView.remove });
要在呼叫回呼函數時提供 this 的內容值,請傳遞選擇性的最後一個參數:model.on('change', this.render, this) 或 model.on({change: this.render}, this)。
offobject.off([event], [callback], [context])
別名:unbind
從物件中移除先前繫結的回呼函數。如果未指定內容,將移除具有不同內容的所有回呼函數版本。如果未指定回呼函數,將移除事件的所有回呼函數。如果未指定事件,將移除所有事件的回呼函數。
// 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(),確實會移除模型上的所有事件,包括 Backbone 用於內部記帳的事件。
triggerobject.trigger(event, [*args])
觸發給定事件或以空白分隔的事件清單的回呼函數。傳遞給觸發的後續參數將傳遞到事件回呼函數。
onceobject.once(event, callback, [context])
就像 on,但會導致繫結的回呼函數僅在移除前觸發一次。對於說「下次 X 發生時,執行此操作」很方便。當使用空白分隔語法傳入多個事件時,事件將針對您傳入的每個事件觸發一次,而不是針對所有事件的組合觸發一次
listenToobject.listenTo(other, event, callback)
告訴物件在其他物件上偵聽特定事件。使用此表單的優點在於,與 other.on(event, callback, object) 相比,listenTo 允許物件追蹤事件,並且它們可以在稍後一次全部移除。回呼函數將始終以物件作為內容呼叫。
view.listenTo(model, 'change', view.render);
stopListeningobject.stopListening([other], [event], [callback])
告訴物件停止偵聽事件。呼叫沒有參數的stopListening,讓物件移除其所有 已註冊 的回呼函數 ... 或更精確地告訴它僅移除它在特定物件、特定事件或僅特定回呼函數上偵聽的事件。
view.stopListening(); view.stopListening(model);
listenToOnceobject.listenToOnce(other, event, callback)
就像 listenTo,但會導致繫結的回呼函數僅在移除前觸發一次。
事件目錄
以下是內建 Backbone 事件的完整清單,包含參數。您也可以自由地在模型、集合和檢視中觸發自己的事件。 Backbone 物件本身會混合 Events,可用於發出應用程式所需的任何全域事件。
一般來說,當呼叫會發出事件的函式(model.set、collection.add 等)時,如果你想防止觸發事件,你可以傳遞 {silent: true} 作為選項。請注意,這很少見,甚至可能從未見過。通常會在事件回呼的選項中傳遞特定旗標以查看並選擇忽略,會比較好。
模型是任何 JavaScript 應用程式的核心,包含互動資料以及其周圍邏輯的大部分:轉換、驗證、計算屬性和存取控制。你可以使用特定於網域的方法來延伸 Backbone.Model,而 Model 提供一組用於管理變更的基本功能。
以下是一個虛構的範例,但它示範了如何定義具有自訂方法的模型、設定屬性,以及觸發與該特定屬性變更相關的事件。執行此程式碼一次後,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 建立的子類別可以進一步延伸和子類別化,直到你滿意為止。
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 沒有提供簡單的方法來呼叫 super,也就是在原型鏈中定義的同名函式。如果你覆寫核心函式,例如 set 或 save,而且你想要呼叫父物件的實作,你必須明確呼叫它,如下所示
var Note = Backbone.Model.extend({ set: function(attributes, options) { Backbone.Model.prototype.set.apply(this, arguments); ... } });
preinitializenew Model([attributes], [options])
用於將模型作為 ES 類別。如果你定義 preinitialize 方法,它會在首次建立 Model 時呼叫,在為 Model 執行任何實例化邏輯之前。
class Country extends Backbone.Model { preinitialize({countryCode}) { this.name = COUNTRY_NAMES[countryCode]; } initialize() { ... } }
建構函式 / initializenew Model([attributes], [options])
在建立模型實例時,你可以傳入 attributes 的初始值,它會在模型上 設定。如果你定義 initialize 函式,它會在建立模型時呼叫。
new Book({ title: "One Thousand and One Nights", author: "Scheherazade" });
在罕見的情況下,如果你想變得花俏,你可能想覆寫 建構函式,這允許你替換模型的實際建構函式。
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: ...} 作為 選項,模型會取得 collection 屬性,用於指出模型所屬的集合,並用於協助計算模型的 網址。model.collection 屬性通常會在您第一次將模型新增到集合時自動建立。請注意,反過來則不成立,因為傳遞此選項給建構函式並不會自動將模型新增到集合中。有時很有用。
如果 {parse: true} 傳遞為 選項,則會先由 parse 轉換 屬性,然後再 設定 到模型上。
getmodel.get(attribute)
從模型取得屬性的目前值。例如:note.get("title")
setmodel.set(attributes, [options])
在模型上設定屬性雜湊(一個或多個)。如果任何屬性變更模型的狀態,則會在模型上觸發 "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 轉譯版本。如果您將資料從模型內插到 HTML 中,使用 escape 來擷取屬性會防止 XSS 攻擊。
var hacker = new Backbone.Model({ name: "<script>alert('xss')</script>" }); alert(hacker.escape('name'));
hasmodel.has(attribute)
如果屬性設定為非 Null 或非未定義值,則傳回 true。
if (note.has("title")) { ... }
unsetmodel.unset(attribute, [options])
從內部屬性雜湊中刪除屬性以移除它。會觸發 "change" 事件,除非傳遞 silent 作為選項。
clearmodel.clear([options])
從模型中移除所有屬性,包括 id 屬性。會觸發 "change" 事件,除非傳遞 silent 作為選項。
idmodel.id
模型的特殊屬性,id 是任意字串(整數 id 或 UUID)。如果您在屬性雜湊中設定 id,它會複製到模型中成為直接屬性。不應直接操作 model.id
,應僅透過 model.set('id', …)
修改。模型可以從集合中依 id 檢索,而且 id 預設用於產生模型 URL。
idAttributemodel.idAttribute
模型的唯一識別碼儲存在 id 屬性下。如果您直接與使用不同唯一金鑰的後端(CouchDB、MongoDB)通訊,您可以設定模型的 idAttribute,以從該金鑰透明地對應到 id。如果您設定 idAttribute,您可能也想要覆寫 cidPrefix。
var Meal = Backbone.Model.extend({ idAttribute: "_id" }); var cake = new Meal({ _id: 1, name: "Cake" }); alert("Cake id: " + cake.id);
cidmodel.cid
模型的特殊屬性,cid 或客戶端 id 是在所有模型第一次建立時自動指派給它們的唯一識別碼。當模型尚未儲存到伺服器,而且尚未有最終的真實 id,但已經需要在 UI 中顯示時,客戶端 id 很方便。
cidPrefixmodel.cidPrefix
如果您的模型的 id 不是整數或 UUID,則有可能與其 cid 衝突。為防止這種情況,您可以覆寫 cid 開頭的前綴。
// If both lengths are 2, refresh the page before running this example. var clashy = new Backbone.Collection([ {id: 'c2'}, {id: 'c1'}, ]); alert('clashy length: ' + clashy.length); var ClashFree = Backbone.Model.extend({cidPrefix: 'm'}); var clashless = new Backbone.Collection([ {id: 'c3'}, {id: 'c2'}, ], {model: ClashFree}); alert('clashless length: ' + clashless.length);
attributesmodel.attributes
attributes 屬性是包含模型狀態的內部雜湊,通常(但並非一定)是表示伺服器上模型資料的 JSON 物件形式。它通常是資料庫中一列的直接序列化,但也可以是客戶端計算的狀態。
請使用 set 更新 attributes,而不是直接修改它們。如果您想要檢索並整理模型屬性的副本,請改用 _.clone(model.attributes)。
由於 事件 接受以空白分隔的事件清單,因此屬性名稱不應包含空白。
changedmodel.changed
changed 屬性是包含自上次 set 以來所有已變更屬性的內部雜湊。請勿直接更新 changed,因為它的狀態是由 set 內部維護的。可從 changedAttributes 取得 changed 的副本。
defaultsmodel.defaults 或 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 定義為函式。
如果您為模型的 idAttribute 設定值,您應該將預設值定義為一個函式,該函式在每次呼叫時都會傳回不同的通用唯一識別碼。如果不這樣做,可能會導致 Backbone.Collection 的實例無法正確識別模型雜湊,而且幾乎肯定會出錯,除非您從未將模型類別的實例新增到集合中。
toJSONmodel.toJSON([options])
傳回模型 attributes 的淺層副本,用於 JSON 字串化。這可以用於持久性、序列化或在傳送至伺服器之前進行擴充。這個方法的名稱有點令人困惑,因為它實際上並未傳回 JSON 字串,但我擔心這是 JSON.stringify 的 JavaScript API 運作的方式。
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])
透過委派給 Backbone.sync 將模型狀態與從伺服器擷取的屬性合併。傳回 jqXHR。如果模型從未填充資料,或您希望確保擁有最新的伺服器狀態,這會很有用。如果伺服器的狀態與目前的屬性不同,"change" 事件會觸發。 fetch 會在選項雜湊中接受 success 和 error 回呼,這兩個回呼都會傳遞 (model, response, options) 作為引數。
// Poll every 10 seconds to keep the channel model up-to-date. setInterval(function() { channel.fetch(); }, 10000);
savemodel.save([attributes], [options])
透過委派給 Backbone.sync 將模型儲存到資料庫(或其他持久性層)。如果驗證成功,會傳回 jqXHR,否則傳回 false。attributes 雜湊(如 set)應包含您想要變更的屬性,未提及的鍵不會變更,但會將資源的完整表示傳送至伺服器。與 set 一樣,您可以傳遞個別鍵和值,而不是雜湊。如果模型有 validate 方法,且驗證失敗,模型不會儲存。如果模型 isNew,儲存會是 "create"(HTTP POST),如果模型已存在於伺服器上,儲存會是 "update"(HTTP PUT)。
如果您只希望將已變更的屬性傳送至伺服器,請呼叫 model.save(attrs, {patch: true})。您會取得傳送至伺服器的 HTTP PATCH 要求,其中僅包含傳入的屬性。
使用新屬性呼叫 save 會立即導致 "change" 事件,當 Ajax 要求開始傳送至伺服器時導致 "request" 事件,以及在伺服器確認成功變更後導致 "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 會在選項雜湊中接受 success 和 error 回呼,這些回呼會傳遞引數 (model, response, options)。如果伺服器端驗證失敗,請傳回非 200 HTTP 回應碼,以及文字或 JSON 格式的錯誤回應。
book.save("author", "F.D.R.", {error: function(){ ... }});
destroymodel.destroy([options])
透過委派 HTTP DELETE 要求至 Backbone.sync,在伺服器上銷毀模型。傳回 jqXHR 物件,或如果模型 isNew,傳回 false。會在選項雜湊中接受 success 和 error 回呼,這些回呼會傳遞 (model, response, options)。在模型上觸發 "destroy" 事件,這個事件會在包含它的任何集合中冒泡,當它開始對伺服器進行 Ajax 要求時觸發 "request" 事件,以及在伺服器成功確認模型的刪除後觸發 "sync" 事件。如果您希望在從集合中移除模型之前等待伺服器回應,請傳遞 {wait: true}。
book.destroy({success: function(model, response) { ... }});
底線方法 (9)
Backbone 代理到 Underscore.js 以在 Backbone.Model 上提供 9 個物件函式。它們並未全部在此記錄,但您可以查看 Underscore 文件以取得完整詳細資料…
user.pick('first_name', 'last_name', 'email'); chapters.keys().join(', ');
validatemodel.validate(attributes, options)
此方法保留未定義,建議您使用任何可在 JavaScript 中執行的自訂驗證邏輯來覆寫它。如果屬性有效,請不要從 validate 傳回任何內容;如果屬性無效,請傳回您選擇的錯誤。它可以簡單到顯示的字串錯誤訊息,或描述錯誤程式化的完整錯誤物件。
預設情況下,save 會在設定任何屬性之前檢查 validate,但您也可以透過傳遞 {validate: true} 作為選項,告訴 set 驗證新的屬性。validate 方法會接收模型屬性以及傳遞給 set 或 save 的任何選項,如果 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(options)
執行 validate 以檢查模型狀態。
validate 方法會接收模型屬性以及傳遞給 isValid 的任何選項,如果 validate 傳回錯誤,"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.set({ start: 15, end: 10 }); if (!one.isValid()) { alert(one.get("title") + " " + one.validationError); }
urlmodel.url()
傳回模型資源在伺服器上會位於的相對 URL。如果您的模型位於其他位置,請使用正確的邏輯覆寫此方法。預設會產生表單 URL:"[collection.url]/[id]",但如果您不考慮模型的集合,您可以透過指定明確的 urlRoot 來覆寫。
委派給 Collection#url 以產生 URL,因此請務必定義它,或 urlRoot 屬性,如果此類別的所有模型共用一個共用根 URL。模型的 id 為 101,儲存在 Backbone.Collection 中,url 為 "/documents/7/notes",將會有此 URL:"/documents/7/notes/101"
urlRootmodel.urlRoot 或 model.urlRoot()
如果您在集合外部使用模型,請指定一個 urlRoot,以啟用預設 url 函式,根據模型 ID 產生 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 後端,您會注意到它的預設 to_json 實作會在命名空間下包含模型的屬性。若要停用此行為以進行無縫的 Backbone 整合,請設定
ActiveRecord::Base.include_root_in_json = false
clonemodel.clone()
傳回一個具有相同屬性的新模型實例。
isNewmodel.isNew()
這個模型是否已儲存到伺服器?如果模型還沒有 id,則認為它是新的。
hasChangedmodel.hasChanged([attribute])
這個模型是否自上次 set 以來已變更?如果傳入一個 attribute,則如果那個特定屬性已變更,傳回 true。
請注意,這個方法和以下與變更相關的方法,僅在 "change" 事件期間才有用。
book.on("change", function() { if (book.hasChanged("title")) { ... } });
changedAttributesmodel.changedAttributes([attributes])
僅擷取自上次 set 以來已變更的模型屬性的雜湊,或如果沒有變更,則擷取 false。選擇性地,可以傳入一個外部 attributes 雜湊,傳回與模型不同的雜湊中的屬性。這可以用於找出檢視的哪些部分應更新,或需要呼叫哪些內容才能將變更同步到伺服器。
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()
傳回模型先前屬性的副本。這對於取得模型版本的差異,或在發生錯誤後回復到有效狀態很有用。
集合是有序的模型集。您可以繫結 "變更" 事件,以便在集合中的任何模型被修改時收到通知,傾聽 "新增" 和 "移除" 事件,從伺服器 擷取 集合,並使用一整套 Underscore.js 方法。
觸發於集合中模型的任何事件也會直接觸發於集合,以方便使用。這讓您可以傾聽集合中任何模型的特定屬性的變更,例如:documents.on("change:selected", ...)
延伸Backbone.Collection.extend(屬性, [類別屬性])
若要建立您自己的 集合類別,請延伸 Backbone.Collection,提供執行個體的 屬性,以及可直接附加至集合建構函式的選用 類別屬性。
模型collection.model([attrs], [選項])
覆寫此屬性,以指定集合包含的模型類別。如果已定義,您可以將原始屬性物件 (和陣列) 和選項傳遞給 新增、建立 和 重設,而屬性將使用提供的選項 (如果有) 轉換成適當類型的模型。
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); } } });
模型 IDcollection.modelId(attrs, idAttribute)
覆寫此方法,以傳回集合將用來識別模型 (給定其屬性) 的值。對於將來自多個資料表 (具有不同的 idAttribute 值) 的模型組合成單一集合很有用。
預設傳回 attrs 中給定 idAttribute 的值,或如果失敗,則傳回 id。如果您的集合使用 模型工廠,而這些模型的 ID 範圍可能會衝突,您必須覆寫此方法。
var Library = Backbone.Collection.extend({ modelId: function(attrs) { return attrs.type + attrs.id; } }); var library = new Library([ {type: 'dvd', id: 1}, {type: 'vhs', id: 1} ]); var dvdId = library.get('dvd1').id; var vhsId = library.get('vhs1').id; alert('dvd: ' + dvdId + ', vhs: ' + vhsId);
預先初始化new Backbone.Collection([模型], [選項])
供搭配集合作為 ES 類別使用。如果您定義 預先初始化方法,它會在集合第一次建立時,以及在集合的任何實例化邏輯執行之前被呼叫。
class Library extends Backbone.Collection { preinitialize() { this.on("add", function() { console.log("Add model event got fired!"); }); } }
建構函式 / 初始化new Backbone.Collection([模型], [選項])
在建立集合時,你可以選擇傳入模型的初始陣列。集合的比較器可以包含為選項。傳入false作為比較器選項將會防止排序。如果你定義一個初始化函數,它將會在集合建立時被呼叫。有幾個選項,如果提供了,會直接附加到集合:model和comparator。
傳入null作為models以使用options建立一個空的集合。
var tabs = new TabSet([tab1, tab2, tab3]); var spaces = new Backbone.Collection(null, { model: Space });
如果{parse: true}被傳入作為一個選項,屬性將會在被設定到集合之前,先被解析。
modelscollection.models
集合內部模型的 JavaScript 陣列的原始存取。通常你會想要使用get、at或底線方法來存取模型物件,但偶爾會需要直接參考陣列。
toJSONcollection.toJSON([options])
傳回一個包含集合中每個模型的屬性雜湊(透過toJSON)的陣列。這可以用來序列化和持久化整個集合。這個方法的名稱有點令人困惑,因為它符合JavaScript 的 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將集合的狀態持久化到伺服器。可以覆寫以自訂行為。
底線方法 (46)
Backbone 代理到Underscore.js以在Backbone.Collection上提供 46 個反覆運算函數。它們並未全部在此記錄,但你可以查看底線文件以取得完整詳細資料…
大多數方法都可以使用物件或字串來支援模型屬性樣式的謂詞或接收模型實例作為參數的函數。
books.each(function(book) { book.publish(); }); var titles = books.map("title"); var publishedBooks = books.filter({published: true}); var alphabetical = books.sortBy(function(book) { return book.author.get("name").toLowerCase(); }); var randomThree = books.sample(3);
新增collection.add(models, [options])
將一個模型 (或一個模型陣列) 新增到集合中,為每個模型觸發一個 "add" 事件,然後觸發一個 "update" 事件。這是一個 set 變體,具有相同的選項和傳回值,但它總是新增,從不移除。如果您要將已經在集合中的模型新增到集合中,它們將會被忽略,除非您傳遞 {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 的模型) 多次新增到集合中
是不會運作的。
移除collection.remove(models, [options])
從集合中移除一個模型 (或一個模型陣列),並傳回它們。每個模型可以是 Model 執行個體、id 字串或 JS 物件,任何可接受為 collection.get 的 id 參數的值。為每個模型觸發一個 "remove" 事件,然後觸發一個單一的 "update" 事件,除非傳遞 {silent: true}。模型在移除前的索引可供監聽者使用,作為 options.index。
重設collection.reset([models], [options])
一次新增和移除模型很好,但有時您有太多模型要變更,您寧可大量更新集合。使用 reset 以新的模型清單 (或屬性雜湊) 取代集合,在完成時觸發單一的 "reset" 事件,且不會在任何模型上觸發任何新增或移除事件。傳回新設定的模型。為了方便起見,在 "reset" 事件中,任何先前模型的清單可作為 options.previousModels 使用。
傳遞 null 給 models 以使用 options 清空您的 Collection。
以下是在 Rails 應用程式中,使用 reset 在初始載入頁面時引導集合的範例
<script> var accounts = new Backbone.Collection; accounts.reset(<%= @accounts.to_json %>); </script>
呼叫 collection.reset() 而沒有傳遞任何模型作為參數,將會清空整個集合。
設定collection.set(models, [options])
set 方法會使用傳遞的模型清單對集合執行「智慧型」更新。如果清單中的模型尚未在集合中,它將會被新增;如果模型已經在集合中,其屬性將會被合併;如果集合包含任何不在清單中的模型,它們將會被移除。所有適當的 "add"、"remove" 和 "change" 事件會在發生時觸發,最後會觸發單一的 "update" 事件。傳回集合中被觸及的模型。如果您想要自訂此行為,您可以使用選項變更它:{add: false}、{remove: false} 或 {merge: false}。
如果定義了 model 屬性,您也可以傳遞原始屬性物件和選項,並使用提供的選項讓它們變成模型執行個體。如果您設定了 比較器,集合將會自動對自己進行排序並觸發 "sort" 事件,除非您傳遞 {sort: false} 或使用 {at: index} 選項。傳遞 {at: index} 以將模型 (或模型陣列) 拼接到集合中指定的 index。
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
與陣列類似,Collection 維護一個 length 屬性,用來計算它包含的模型數量。
comparatorcollection.comparator
預設情況下,集合沒有 comparator。如果你定義一個 comparator,它會在新增模型時用來排序集合。comparator 可以定義為 sortBy(傳入一個函式,該函式只接受一個引數)、sort(傳入一個 comparator 函式,該函式需要兩個引數)或一個字串,表示要依據哪個屬性排序。
"sortBy" comparator 函式會接受一個模型,並傳回一個數字或字串值,用來決定模型相對於其他模型的排序方式。"sort" comparator 函式會接受兩個模型,並傳回 -1(如果第一個模型應該排在第二個模型之前)、0(如果它們的排名相同)或 1(如果第一個模型應該排在第二個模型之後)。請注意,Backbone 會根據 comparator 函式的引數個數來判斷這兩種樣式,因此如果你繫結了 comparator 函式,請務必小心。
請注意,儘管此範例中的所有章節都是反向新增的,但它們仍會以正確的順序顯示
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])
強制集合重新排序。請注意,具有 比較器 的集合會在新增模型時自動排序。若要在新增模型時停用排序,請將 {sort: false} 傳遞給 add。呼叫 sort 會在集合上觸發 "sort" 事件。
pluckcollection.pluck(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,但直接只傳回集合中第一個符合傳遞的 attributes 的模型。如果沒有模型符合,則傳回 undefined。
urlcollection.url or collection.url()
設定集合上的 url 屬性 (或函式) 以參照其在伺服器上的位置。集合中的模型會使用 url 來建構它們自己的 URL。
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)
每當集合的模型由伺服器傳回時,Backbone 會呼叫 parse,在 fetch 中。函式會傳遞原始 response 物件,並應傳回要 新增 到集合的模型屬性陣列。預設實作是空操作,僅傳遞 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])
從伺服器擷取此集合的預設模型組,設定它們在到達時在集合上。選項雜湊採用 success 和 error 回呼,兩者都將傳遞 (collection, response, options) 作為引數。當模型資料從伺服器傳回時,它使用 set 來(智慧地)合併擷取的模型,除非您傳遞 {reset: true},在這種情況下,集合將(有效地)重設。委派給 Backbone.sync 隱藏自訂持久化策略,並傳回 jqXHR。擷取要求的伺服器處理常式應傳回模型的 JSON 陣列。
Backbone.sync = function(method, model) { alert(method + ": " + model.url); }; var accounts = new Backbone.Collection; accounts.url = '/accounts'; accounts.fetch();
擷取的行為可透過使用可用的 set 選項自訂。例如,要擷取集合,取得每個新模型的 "add" 事件,以及每個已變更現有模型的 "change" 事件,而不移除任何內容:collection.fetch({remove: false})
jQuery.ajax 選項也可以直接傳遞為 擷取選項,因此要擷取分頁集合的特定頁面:Documents.fetch({data: {page: 3}})
請注意,擷取不應使用於在頁面載入時填入集合 - 載入時間所需的所有模型都應已引導到位。擷取旨在為不需要立即的介面延遲載入模型:例如,具有可能開啟和關閉的筆記集合的文件。
建立collection.create(attributes, [options])
方便在集合中建立模型的新執行個體。等同於使用屬性雜湊建立模型執行個體,將模型儲存到伺服器,並在成功建立後將模型新增到組中。傳回新模型。如果用戶端驗證失敗,模型將不會儲存,並出現驗證錯誤。為了讓此方法運作,您應設定集合的 model 屬性。建立方法可以接受屬性雜湊和在模型建立期間傳遞的選項,或現有的未儲存模型物件。
建立模型會觸發集合中的立即"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" });
mixinBackbone.Collection.mixin(properties)
mixin
提供一種增強基本Backbone.Collection和延伸它的任何集合的方法。這可以用於新增一般方法(例如其他底線方法)。
Backbone.Collection.mixin({ sum: function(models, iteratee) { return _.reduce(models, function(s, m) { return s + iteratee(m); }, 0); } }); var cart = new Backbone.Collection([ {price: 16, name: 'monopoly'}, {price: 5, name: 'deck of cards'}, {price: 20, name: 'chess'} ]); var cost = cart.sum('price');
Web 應用程式通常會提供可連結、可加入書籤、可分享的 URL,以連結至應用程式中重要的位置。直到最近,雜湊片段 (#page) 才用於提供這些永久連結,但隨著 History API 的出現,現在可以使用標準 URL (/page)。Backbone.Router 提供方法來路由用戶端頁面,並將它們連結至動作和事件。對於尚未支援 History API 的瀏覽器,Router 會處理優雅的備援和 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 雜湊將帶有參數的 URL 對應至路由器上的函式(或如果您偏好,僅對應至直接函式定義),類似於View的events 雜湊。路由可以包含參數部分 :param,它會在斜線之間對應單一 URL 組成部分;以及 splat 部分 *splat,它可以對應任何數量的 URL 組成部分。路由的一部分可以透過將其括在圓括號中 (/:optional) 來設為選用。
例如,路由 "search/:query/p:page" 會對應 #search/obama/p2 片段,將 "obama" 和 "2" 傳遞至動作作為位置參數。
路由 "file/*path" 會對應 #file/folder/file.txt,將 "folder/file.txt" 傳遞至動作。
路由 "docs/:section(/:subsection)" 會對應 #docs/faq 和 #docs/faq/installing,在第一個情況下將 "faq" 傳遞至動作,在第二個情況下將 "faq" 和 "installing" 傳遞至動作。
巢狀選用路由 "docs(/:section)(/:subsection)" 會對應 #docs、#docs/faq 和 #docs/faq/installing,在第二個情況下將 "faq" 傳遞至動作,在第三個情況下將 "faq" 和 "installing" 傳遞至動作。
尾部斜線視為 URL 的一部分,且在存取時(正確地)視為一個唯一的路由。docs 和 docs/ 會觸發不同的回呼。如果您無法避免產生這兩種類型的 URL,您可以定義一個 "docs(/)" 比對器來擷取這兩種情況。
當訪客按下返回按鈕或輸入 URL,且比對到特定路由時,動作的名稱會作為一個 事件 觸發,以便其他物件可以監聽路由器並收到通知。在以下範例中,拜訪 #help/uploading 會從路由器觸發一個 route:help 事件。
routes: { "help/:page": "help", "download/*path": "download", "folder/:name": "openFolder", "folder/:name-:mode": "openFolder" }
router.on("route:help", function(page) { ... });
preinitializenew Backbone.Router([options])
與路由器一起用於 ES 類別。如果您定義一個 preinitialize 方法,它會在路由器第一次建立時和執行路由器的任何實例化邏輯之前被呼叫。
class Router extends Backbone.Router { preinitialize() { // Override execute method this.execute = function(callback, args, name) { if (!loggedIn) { goToLogin(); return false; } args.push(parseQueryString(args.pop())); if (callback) callback.apply(this, args); } } }
建構函式 / initializenew Router([options])
在建立新的路由器時,您可以選擇將其 路由 哈希直接傳遞為選項。如果已定義,所有 options 也會傳遞給您的 initialize 函式。
路由router.route(route, name, [callback])
手動為路由器建立一個路由,route 參數可以是 路由字串 或正規表示式。從路由或正規表示式比對到的每個相符擷取都會作為參數傳遞給回呼。每當比對到路由時,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) { ... }
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});
執行router.execute(callback, args, name)
每當路由比對到且其對應的 callback 即將執行時,此方法會在路由器內部呼叫。從 execute 傳回 false 以取消目前的轉換。覆寫它以執行路由的客製化剖析或包裝,例如在將查詢字串傳遞給路由回呼之前剖析查詢字串,如下所示
var Router = Backbone.Router.extend({ execute: function(callback, args, name) { if (!loggedIn) { goToLogin(); return false; } args.push(parseQueryString(args.pop())); if (callback) callback.apply(this, args); } });
歷史記錄用作全域路由器(每幀),以處理 hashchange 事件或 pushState,比對適當的路由,並觸發回呼。它會轉發比對路由器的 "route" 和 "route[name]" 事件,或當任何路由器中的路由與目前 URL 不相符時轉發 "notfound"。由於 Backbone.history 已包含一個,因此您不應該建立自己的路由器。
pushState 支援在 Backbone 中完全採用選擇加入的方式。不支援 pushState 的舊瀏覽器將繼續使用基於雜湊的 URL 片段,如果 pushState 相容瀏覽器造訪雜湊 URL,它將透明地升級為真實 URL。請注意,使用真實 URL 需要您的網路伺服器能夠正確呈現這些頁面,因此也需要後端變更。例如,如果您有一個 /documents/100 路由,當瀏覽器直接造訪該 URL 時,您的網路伺服器必須能夠提供該頁面。為了完整搜尋引擎可爬取性,最好讓伺服器產生頁面的完整 HTML ... 但如果它是一個網路應用程式,只要呈現您會用於根 URL 的相同內容,並使用 Backbone Views 和 JavaScript 填入其餘部分即可。
startBackbone.history.start([options])
當您的所有 路由器 已建立,且所有路由都已正確設定後,請呼叫 Backbone.history.start() 以開始監控 hashchange 事件,並分派路由。後續呼叫 Backbone.history.start() 會擲回錯誤,而 Backbone.History.started 是布林值,表示它是否已呼叫。
若要指出您想在應用程式中使用 HTML5 pushState 支援,請使用 Backbone.history.start({pushState: true})。如果您想使用 pushState,但讓不原生支援它的瀏覽器改用完整頁面重新整理,您可以將 {hashChange: false} 加入選項。
如果您的應用程式不是從網域的根 URL / 提供,請務必告訴 History 根實際在哪裡,作為選項:Backbone.history.start({pushState: true, root: "/public/search/"})。
提供給 root 的值會正規化,以包含前導和尾隨斜線。導覽到路由時,預設行為會從 URL 排除尾隨斜線(例如,/public/search?query=...)。如果您偏好包含尾隨斜線(例如,/public/search/?query=...),請使用 Backbone.history.start({trailingSlash: true})。URL 始終會包含前導斜線。當 root 是 / 時,URL 會看起來像 /?query=...,而與 trailingSlash 的值無關。
呼叫時,如果某個路由成功與目前的 URL 相符,Backbone.history.start() 會傳回 true,並觸發 "route" 和 "route[name]" 事件。如果沒有已定義的路由與目前的 URL 相符,則會傳回 false,並觸發 "notfound"。
如果伺服器已呈現整個頁面,而且您不希望在開始記錄時觸發初始路由,請傳遞 silent: true。
由於 Internet Explorer 中的雜湊式記錄依賴於 <iframe>,因此請務必在 DOM 準備好後才呼叫 start()。
$(function(){ new WorkspaceRouter(); new HelpPaneRouter(); Backbone.history.start({pushState: true}); });
Backbone.sync 是 Backbone 在每次嘗試讀取或將模型儲存到伺服器時呼叫的函數。預設情況下,它會使用 jQuery.ajax 進行 RESTful JSON 要求,並傳回 jqXHR。您可以覆寫它以使用不同的持久性策略,例如 WebSockets、XML 傳輸或 Local Storage。
Backbone.sync 的方法簽章為 sync(method, model, [options])
使用預設實作時,當 Backbone.sync 傳送要求以儲存模型時,其屬性會傳遞、序列化為 JSON,並在 HTTP 主體中以內容類型 application/json 傳送。傳回 JSON 回應時,傳送伺服器已變更的模型屬性,且需要在用戶端更新。回應集合的 "read" 要求 (Collection#fetch) 時,傳送模型屬性物件陣列。
每當模型或集合開始與伺服器進行 sync 時,就會發出 "request" 事件。如果要求成功完成,您會收到 "sync" 事件,如果沒有,則會收到 "error" 事件。
sync 函數可以全局覆寫為 Backbone.sync,或透過將 sync 函數新增到 Backbone 集合或個別模型,以更細緻的層級覆寫。
預設的 sync 處理常式將 CRUD 對應到 REST,如下所示
舉例來說,回應 Backbone 的 "update" 呼叫的 Rails 4 處理常式可能如下所示
def update account = Account.find params[:id] permitted = params.require(:account).permit(:name, :otherparam) account.update_attributes permitted render :json => account end
整合 3.1 之前的 Rails 版本的另一個提示是,透過設定 ActiveRecord::Base.include_root_in_json = false 來停用模型上 to_json 呼叫的預設命名空間。
ajaxBackbone.ajax = function(request) { ... };
如果您想要使用自訂 AJAX 函數,或您的端點不支援 jQuery.ajax API,而且您需要調整設定,您可以透過設定 Backbone.ajax 來執行此操作。
emulateHTTPBackbone.emulateHTTP = true
如果您想使用不支援 Backbone 預設 REST/HTTP 方法的舊式網路伺服器,您可以選擇開啟 Backbone.emulateHTTP。設定此選項會使用 HTTP POST 模擬 PUT、PATCH 和 DELETE 要求,並將 X-HTTP-Method-Override 標頭設定為真實方法。如果 emulateJSON 也已開啟,真實方法將傳遞為額外的 _method 參數。
Backbone.emulateHTTP = true; model.save(); // POST to "/collection/id", with "_method=PUT" + header.
emulateJSONBackbone.emulateJSON = true
如果您使用無法處理編碼為 application/json 的要求的舊式網路伺服器,設定 Backbone.emulateJSON = true; 會導致 JSON 在 model 參數下序列化,並使用 application/x-www-form-urlencoded MIME 類型發出要求,就像來自 HTML 表單一樣。
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 等屬性,也可以將它們定義為函式。
preinitializenew View([options])
用於 ES 類別的視圖。如果您定義 preinitialize 方法,它會在視圖第一次建立時呼叫,在執行任何建立邏輯之前。
class Document extends Backbone.View { preinitialize({autoRender}) { this.autoRender = autoRender; } initialize() { if (this.autoRender) { this.listenTo(this.model, "change", this.render); } } }
constructor / initializenew View([options])
有幾個特殊選項,如果傳遞,將直接附加到視圖:model、collection、el、id、className、tagName、attributes 和 events。如果視圖定義 initialize 函式,它會在視圖第一次建立時呼叫。如果您想建立一個參照 DOM 中已經存在元素的視圖,請將元素作為選項傳入:new View({el: existingElement})
var doc = documents.first(); new DocumentRow({ model: doc, id: "document-row-" + doc.id });
elview.el
所有檢視在任何時候都有一個 DOM 元素(el 屬性),無論它們是否已插入頁面。這樣,檢視可以在任何時候呈現,並一次插入 DOM,以便以最少的重排和重繪取得高性能 UI 呈現。
this.el 可以從 DOM 選擇器字串或元素解析;否則,它將從檢視的 tagName、className、id 和 attributes 屬性建立。如果沒有設定任何屬性,this.el 是空的 div,這通常就足夠了。也可以將 el 參照傳遞到檢視的建構函式中。
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 元素屬性(id、類別、資料屬性等),或傳回此類雜湊的函式。
$ (jQuery)view.$(selector)
如果頁面上包含 jQuery,每個檢視都有 $ 函式,可在檢視元素的範圍內執行查詢。如果您使用這個範圍化的 jQuery 函式,您不必使用模型 id 作為查詢的一部分來抽出清單中的特定元素,而且可以更依賴 HTML 類別屬性。它等於執行: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 函式是很好的慣例。這樣,在呈現檢視時,您可以方便地存取實例資料。例如,使用底線範本
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 已在頁面上,_.template 可用,如果您偏好簡單的內插 JavaScript 風格範本,它是一個絕佳的選擇。
無論您採用哪種範本策略,如果永遠不必在 JavaScript 中放入 HTML 字串,那就太好了。在 DocumentCloud 中,我們使用 Jammit 將儲存在 /app/views 中的 JavaScript 範本打包為我們的 core.js 主要資產套件的一部分。
removeview.remove()
移除檢視及其 el 從 DOM,並呼叫 stopListening 來移除檢視已 listenTo 的任何繫結事件。
事件view.events 或 view.events()
事件雜湊(或方法)可用於指定一組 DOM 事件,這些事件將透過 delegateEvents 繫結到檢視中的方法。
Backbone 會在實例化時自動附加事件監聽器,在呼叫 initialize 之前。
var ENTER_KEY = 13; var InputView = Backbone.View.extend({ tagName: 'input', events: { "keydown" : "keyAction", }, render: function() { ... }, keyAction: function(e) { if (e.which === ENTER_KEY) { this.collection.add({text: this.$el.val()}); } } });
delegateEventsdelegateEvents([events])
使用 jQuery 的 on 函數,為檢視中的 DOM 事件提供宣告式回呼。如果未直接傳遞 事件雜湊,則使用 this.events 作為來源。事件以 {"event selector": "callback"} 格式撰寫。回呼可能是檢視中方法的名稱,或直接函數主體。省略 selector 會導致事件繫結到檢視的根元素 (this.el)。預設情況下,delegateEvents 會在檢視的建構函式中為您呼叫,因此如果您有一個簡單的 events 雜湊,則所有 DOM 事件將永遠都已連接,而且您永遠不必自己呼叫此函數。
events 屬性也可以定義為傳回 events 雜湊的函數,以簡化以程式方式定義事件,以及從父檢視繼承事件。
使用 delegateEvents 有一些優點,優於在 render 期間手動使用 jQuery 將事件繫結到子元素。所有附加的回呼都會在傳遞給 jQuery 之前繫結到檢視,因此當呼叫回呼時,this 會繼續參照檢視物件。當 delegateEvents 再次執行時,可能使用不同的 events 雜湊,所有回呼都會被移除並重新委派,這對於在不同模式下需要表現不同的檢視很有用。
delegateEvents 的單一事件版本可用作 delegate。事實上,delegateEvents 只是 delegate 周圍的多重事件包裝器。與 undelegateEvents 對應的版本可用作 undelegate。
在搜尋結果中顯示文件的檢視可能如下所示
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 中的檢視,這會很有用。
Backbone.noConflictvar backbone = Backbone.noConflict();
將 Backbone 物件還原成原始值。你可以使用 Backbone.noConflict() 的回傳值來保留 Backbone 的區域參考。這對於在第三方網站中嵌入 Backbone 很實用,因為你不想覆蓋現有的 Backbone。
var localBackbone = Backbone.noConflict(); var model = localBackbone.Model.extend(...);
Backbone.$Backbone.$ = $;
如果你在頁面上有多個 jQuery 副本,或者只是想告訴 Backbone 使用特定物件作為其 DOM/Ajax 函式庫,這就是你的屬性。
Backbone.$ = require('jquery');
debugInfodebugInfo();
在不幸需要提交 錯誤報告 的情況下,此函式可以更容易地提供有關你的設定的詳細資訊。它透過 console.debug 列印一個 JSON 物件,其中包含有關 Backbone 及其相依項的版本資訊。如果你想在程式碼中檢查它,它也會回傳這個物件。
debugInfo 在一個獨立的模組中,與 邊緣版本 和 1.5.0 之後發布的版本一起提供。它以 UMD 格式提供,與 backbone.js 的前綴相同,但檔案名稱為 debug-info.js。它也可以在 backbone/modules/ 下以 ES 模組格式進行實驗性提供。
<!-- browser embeds --> <script src="some-path-or-url/backbone.js"></script> <script src="some-path-or-url/debug-info.js"></script> <script> Backbone.debugInfo(); </script> // CommonJS require('backbone/debug-info.js')(); // ESM import debugInfo from 'backbone/modules/debug-info.js'; debugInfo();
為什麼要使用 Backbone,而不是 [其他框架 X]?
如果你的目光還沒有被上面 範例清單 中展現的適應性和熱情所吸引,我們可以更具體說明:Backbone.js 旨在提供資料豐富的網路應用程式所需的共同基礎,並具有雄心勃勃的介面 — 同時非常謹慎地避免讓你陷入困境,做出你更適合自己做出的任何決定。
有多種方法可以做到
對於剛入門的人來說,將此頁面上列出的範例視為某種神聖真理是很常見的。事實上,Backbone.js 旨在對客戶端程式碼中的許多常見模式保持相當程度的不可知論。例如...
模型與檢視之間的關聯可以透過多種方式處理。有些人喜歡有直接指標,其中檢視與模型以 1:1 對應(model.view 和 view.model)。其他人則偏好有中介的「控制器」物件,用來協調檢視的建立和組織,形成階層。還有人偏好事件導向的方法,並總是觸發事件,而不是直接呼叫方法。這些風格都很好用。
批次作業在模型上很常見,但通常最好根據您的伺服器端設定以不同的方式處理。有些人不在乎建立個別的 Ajax 要求。其他人則為 RESTful 批次作業建立明確的資源:/notes/batch/destroy?ids=1,2,3,4。其他人則透過 JSON 隧道傳送 REST,建立「變更集」要求
{ "create": [array of models to create] "update": [array of models to update] "destroy": [array of model ids to destroy] }
請隨時定義您自己的事件。Backbone.Events 的設計讓您可以將它混入任何 JavaScript 物件或原型。由於您可以使用任何字串作為事件,因此繫結和觸發您自己的自訂事件通常很方便:model.on("selected:true") 或 model.on("editing")
視需要呈現 UI。Backbone 對於您在 render 函式中使用 底線樣板、Mustache.js、直接 DOM 操作、伺服器端呈現的 HTML 片段或 jQuery UI,並無特定偏好。有時您會為每個模型建立一個檢視…有時您會有一個檢視一次在緊密迴圈中呈現數千個模型。這兩種方式都可以在同一個應用程式中適當地使用,具體取決於所涉及的資料量和 UI 的複雜性。
巢狀模型和集合
在 Backbone 中,將集合巢狀在模型中很常見。例如,考慮一個包含許多 Message 模型的 Mailbox 模型。處理此問題的一個不錯的模式是為每個郵件信箱建立一個 this.messages 集合,讓郵件信箱在第一次開啟時可以延遲載入郵件…也許透過 MessageList 檢視來偵聽 "add" 和 "remove" 事件。
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});
如果您正在尋找更具主見的東西,有許多 Backbone 外掛程式會在模型之間加入精密的關聯,可以在 wiki 上取得。
Backbone 不包含對巢狀模型和集合或「多對多」關聯的直接支援,因為有許多良好的模式可以在客戶端建模結構化資料,而且Backbone 應該提供實作任何模式的基礎。您可能想要…
載入引導模型
當你的應用程式第一次載入時,通常會有一組你已知的初始模型,以便呈現頁面。與其發出額外的 AJAX 要求來 擷取 它們,一個較好的模式是將它們的資料已開機自訂程式載入頁面。然後你可以使用 重設 來使用初始資料填入你的集合。在 DocumentCloud 中,在工作區的 ERB 範本中,我們會執行類似以下的動作
<script> var accounts = new Backbone.Collection; accounts.reset(<%= @accounts.to_json %>); var projects = new Backbone.Collection; projects.reset(<%= @projects.to_json(:collaborators => true) %>); </script>
你必須在 JSON 字串中 跳脫 </,以防止 JavaScript 注入攻擊。
延伸 Backbone
許多 JavaScript 函式庫旨在成為孤立且封閉的,你透過呼叫它們的公開 API 與它們互動,但絕不會深入了解內部結構。Backbone.js 不是 這種函式庫。
由於它作為應用程式的基礎,因此你應該以你認為合適的方式延伸和增強它 — 完整的原始碼已 加註解,讓你可以更輕鬆地執行此動作。你會發現除了核心功能之外,那裡幾乎沒有其他內容,而且大多數功能都可以被覆寫或擴充,如果你發現有需要的話。如果你發現自己將方法新增到 Backbone.Model.prototype,或建立你自己的基本子類別,請不用擔心 — 事情就是應該這樣運作的。
Backbone 與「傳統」MVC 有何關係?
不同的 模型-檢視-控制器 模式實作往往對於控制器的定義意見不一。如果這有任何幫助,在 Backbone 中,檢視 類別也可以被視為一種控制器,它會傳送源自於 UI 的事件,而 HTML 範本則作為真正的檢視。我們稱它為檢視,因為它代表 UI 的邏輯區塊,負責單一 DOM 元素的內容。
將 Backbone 的整體結構與像是 Rails 的伺服器端 MVC 架構進行比較,各個部分的對應如下
繫結「this」
可能最常見的 JavaScript「陷阱」是,當你將函式傳遞為回呼時,其 this 的值會遺失。在 Backbone 中處理 事件 和回呼時,你通常會發現依賴 listenTo 或許多 Underscore 和 Backbone 方法使用的可選 context 參數很有用,這些參數用於指定稍後呼叫回呼時將使用的 this。(請參閱 _.each、_.map 和 object.on,僅舉幾例)。檢視事件會自動繫結到檢視的內容。你可能還會發現使用 Underscore.js 中的 _.bind 和 _.bindAll 有用。
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);
與 Rails 合作
Backbone.js 最初從 Rails 應用程式中提取;讓你的客戶端(Backbone)模型與你的伺服器端(Rails)模型正確同步並不費力,但仍有一些事項需要注意。
預設情況下,3.1 之前的 Rails 版本會在模型的 JSON 表示法周圍新增額外的包裝層。你可以透過設定
ActiveRecord::Base.include_root_in_json = false
... 在你的設定中停用此包裝。否則,請覆寫 parse 以從包裝中提取模型屬性。類似地,Backbone PUT 和 POST 直接將模型的 JSON 表示法,而預設情況下 Rails 預期命名空間屬性。你可以讓你的控制器直接從 params 過濾屬性,或者你可以覆寫 Backbone 中的 toJSON 以新增 Rails 預期的額外包裝。
以下範例清單雖然很長,但並非詳盡無遺,也並非任何方式的最新資訊。如果你曾經使用 Backbone 的應用程式,請將其新增到 Backbone 應用程式的 wiki 頁面。
Jérôme Gravel-Niquet 已貢獻一個 待辦事項清單應用程式,該應用程式以 Backbone 範例的形式打包在儲存庫中。如果你想知道一般來說從何處開始使用 Backbone,請花點時間 閱讀附註來源。此應用程式使用 LocalStorage 適配器 透明地儲存你瀏覽器中的所有待辦事項,而不是將它們傳送到伺服器。Jérôme 也有託管在 localtodos.com 的版本。
DocumentCloud 工作區建立在 Backbone.js 上,其中包含文件、專案、筆記和帳戶,所有這些都是 Backbone 模型和集合。如果您有興趣了解歷史,Underscore.js 和 Backbone.js 最初都是從 DocumentCloud 程式碼庫中提取出來,並封裝成獨立的 JS 函式庫。
今日美國利用 Backbone 資料/模型生命週期的模組化,這使得建立、繼承、隔離和連結應用程式物件變得簡單,讓程式碼庫既易於管理又有效率。新網站也大量使用 Backbone 路由器來控制支援 pushState 的瀏覽器和舊版瀏覽器的頁面。最後,團隊利用 Backbone 的事件模組建立了一個 PubSub API,讓第三方和分析套件可以連接到應用程式的核心。
新 Rdio從頭開始開發,採用基於 Backbone.js 的元件架構。螢幕上的每個元件都是動態載入和呈現的,資料由Rdio API提供。當變更被推播時,每個元件都可以更新自身,而不會重新載入頁面或中斷使用者的音樂。所有這些都依賴 Backbone 的檢視和模型,而所有 URL 路由都由 Backbone 的路由器處理。當資料變更在即時中發出訊號時,Backbone 的事件會通知感興趣的元件資料變更。Backbone 構成新的、動態的、即時的 Rdio 網路和桌面應用程式的核心。
Hulu使用 Backbone.js 建立其下一代線上影片體驗。以 Backbone 為基礎,網路介面從頭開始重新撰寫,讓所有頁面內容可以在您瀏覽時動態載入,並有順暢的轉場。Backbone 讓您可以在不重新載入腳本和嵌入式影片的情況下快速瀏覽應用程式,同時也提供模型和集合,以提供額外的資料處理支援。
Quartz將自己視為新全球經濟的數位原生新聞媒體。由於 Quartz 相信開放、跨平台網路應用程式的未來,因此他們選擇 Backbone 和 Underscore 來擷取、排序、儲存和顯示來自自訂 WordPress API 的內容。儘管qz.com對手機、平板電腦和桌上型電腦瀏覽器使用回應式設計,但在某些情況下,它也會利用 Backbone 事件和檢視來呈現特定於裝置的範本。
Earth.nullschool.net在互動式動畫地球儀上顯示即時天氣狀況,而 Backbone 提供了網站所有元件建立的基礎。儘管存在其他幾個 JavaScript 函式庫,但 Backbone 的非意見化設計讓它可以毫不費力地混合事件功能,用於在整個頁面上分發狀態變更。當決定轉換到 Backbone 時,大量的自訂邏輯區塊就消失了。
Vox Media,SB Nation、The Verge、Polygon、Eater、Racked、Curbed 和 Vox.com 的出版商,在其自有出版平台 Chorus 中全面使用 Backbone,Chorus 是其自有出版平台。Backbone 為 Vox Media 所有屬性中使用的 部落格即時更新平台 和 評論系統 提供支援;Coverage,一個內部編輯協調工具;SB Nation Live,一個即時事件報導和聊天工具;以及 Vox Cards,Vox.com 的螢光筆和索引卡靈感應用程式,用於提供新聞背景。
Kinja 是 Gawker Media 的出版平台,旨在透過打破內容創作者和消費者傳統角色之間的界線來創作精彩的故事。每個人(編輯、讀者、行銷人員)都可以使用相同的工具參與熱烈討論並追求故事的真相。在 Kinja 生態系統中分享、推薦和追蹤,可以改善所有網站上的資訊探索。
Kinja 是 Gawker、Gizmodo、Lifehacker、io9 和其他 Gawker Media 部落格背後的平台。Backbone.js 是前端應用程式程式碼的基礎,為從使用者驗證到文章撰寫、評論,甚至投放廣告的所有功能提供支援。JavaScript 堆疊包括 Underscore.js 和 jQuery,以及一些外掛程式,全部使用 RequireJS 載入。Closure 範本在基於 Play! Framework 的 Scala 應用程式和 Backbone 檢視之間共享,而回應式版面配置則是使用 Foundation 框架和 SASS 完成。
MetaLab 使用 Backbone.js 建立 Flow,一個團隊任務管理應用程式。工作區依賴 Backbone.js 建構任務檢視、活動、帳戶、資料夾、專案和標籤。您可以在 window.Flow 下看到內部結構。
Gilt Groupe 使用 Backbone.js 建立其網站家族中的多個應用程式。 Gilt 的行動網站 使用 Backbone 和 Zepto.js 為行動中的使用者創造極速的購物體驗,而 Gilt Live 則結合 Backbone 和 WebSockets 來顯示顧客正在購買的商品。Gilt 的搜尋功能也使用 Backbone 來有效率地過濾和分類產品,方法是將這些動作移至用戶端。
Enigma 是個入口網站,彙整政府、大學、公司和組織所產出的最大公共資料集合。Enigma 使用 Backbone 模型和集合來表示複雜的資料結構;而 Backbone 的路由器則提供 Enigma 使用者獨特的應用程式狀態 URL,讓他們能夠在網站中快速導覽,同時還能書籤頁面並在瀏覽期間前進和後退。
NewsBlur 是個 RSS 訂閱閱讀器和社交新聞網路,擁有快速且靈敏的使用者介面,感覺就像原生桌面應用程式。Backbone.js 被選用來進行 重寫和從混亂程式碼轉換,原因在於它功能強大但簡單、容易整合,而且社群龐大。如果您想深入了解,NewsBlur 也是完全 開源 的。
WordPress.com 是 WordPress 的軟體即服務版本。它在 通知系統 中使用 Backbone.js 模型、集合和檢視。選擇 Backbone.js 的原因在於它很容易融入應用程式的結構,而不是相反。 Automattic(WordPress.com 背後的公司)正在將 Backbone.js 整合到統計資料標籤和其他功能中,遍及整個首頁。
Foursquare 是個有趣的小型新創公司,可以幫助您與朋友見面、發現新地點和省錢。Backbone 模型在核心 JavaScript API 層中被大量使用,而檢視則支援許多熱門功能,例如 首頁地圖 和 清單。
Bitbucket 是個免費的 Git 和 Mercurial 原始碼寄存服務。透過其模型和集合,Backbone.js 已證明對支援 Bitbucket 的 REST API 很有價值,以及較新的元件,例如內嵌程式碼註解和拉取要求核准。Mustache 範本提供伺服器和用戶端側的呈現,而一個自訂的、受 Google Closure 啟發的 widget 生命週期則讓 Bitbucket 能裝飾現有的 DOM 樹並插入新的 DOM 樹。
Disqus 選擇 Backbone.js 來支援其最新版本的留言 widget。Backbone 的體積小且容易擴充,使其成為 Disqus 分散式網路應用程式的正確選擇,而該應用程式完全寄存在 iframe 中,並在數千個大型網站屬性中提供服務,包括 IGN、Wired、CNN、MLB 等。
Delicious 是一個社交書籤平台,可以輕鬆儲存、分類和儲存來自網路的書籤。Delicious 使用 Chaplin.js、Backbone.js 和 AppCache 來建置一個功能齊全的 MVC 網路應用程式。Backbone 的使用有助於網站和 行動應用程式 共享單一 API 服務,而模型層的重複使用讓在最近 Delicious 重新設計期間共享程式碼變得容易許多。
可汗學院 的任務是為任何地方的任何人提供免費的世界級教育。可汗學院使用 Backbone 來讓前端程式碼保持模組化和有條理,並擁有數千部影片、數百個由 JavaScript 驅動的練習以及對未來的宏偉計畫。使用者個人資料和目標設定是使用 Backbone、jQuery 和 Handlebars 執行的,而且大部分新功能工作都推送到客戶端,大幅提升 API 的品質。
IRCCloud 是一個始終連線的 IRC 客戶端,您可以在瀏覽器中使用它,通常會在一個分頁中整天開啟它。流暢的網路介面透過網路套接字和 IRCCloud API 與 Erlang 後端通訊。它大量使用 Backbone.js 事件、模型、檢視和路由,讓您的 IRC 對話可以即時進行。
Pitchfork 使用 Backbone.js 來強化其全站音訊播放器、Pitchfork.tv、位置路由、寫入式頁面片段快取等功能。Backbone.js(和 Underscore.js)有助於團隊建立乾淨且模組化的元件、快速移動,並專注於網站,而不是雜亂無章的程式。
Spin 使用 Backbone 模型和集合,以及自訂 sync 方法,從其內部 API 中擷取 最新新聞報導 到其網站上。由於音樂不應停止播放,即使您點選到不同的「頁面」,Spin 也會使用 Backbone 路由器在網站內導覽。
ZocDoc 協助病患找到當地、在網路內的醫生和牙醫,查看其即時可看診時間,並立即預約。在公開面,網路應用程式使用 Backbone.js 來處理客戶端狀態,並在 搜尋頁面 和 醫生個人資料 中進行呈現。此外,網站中面向醫生的部分的新版本是一個大型單頁應用程式,受益於 Backbone 的結構和模組化。ZocDoc 的 Backbone 類別會使用 Jasmine 進行測試,並透過 Cassette 傳遞給最終使用者。
沃爾瑪 使用 Backbone.js 建立新版本的 行動版網頁應用程式,並在此過程中建立兩個新架構。 Thorax 提供混入、可繼承事件,以及與 Handlebars 範本直接整合的模型和集合檢視繫結。 Lumbar 允許應用程式分割成可依需求載入的模組,並為嵌入在沃爾瑪原生 Android 和 iOS 應用程式的網頁應用程式部分建立特定於平台的建置。
Groupon Now! 協助您找到可立即購買並使用的在地優惠。在首次開發產品時,團隊決定採用大量的 AJAX,並在各區段之間進行順暢的轉換,而非完全重新整理,但仍需要完全可連結且可分享。儘管從未使用過 Backbone,但學習曲線卻快得令人難以置信 — 在一個下午就編寫出原型,而團隊也在兩週內就推出產品。由於原始碼精簡且易於理解,因此很容易為 Groupon Now!新增數個 Backbone 擴充功能:變更路由器以處理含有查詢字串參數的 URL,以及新增一個簡單的記憶體內儲存體,以快取對相同資料的重複要求。
37Signals 選擇 Backbone.js 來建立其熱門專案管理軟體 Basecamp 的 行事曆功能。Basecamp 行事曆使用 Backbone.js 模型和檢視,搭配 Eco 範本系統,以呈現精緻且高度互動的群組排程介面。
奴隸足跡 讓消費者了解他們的消費習慣如何與現代奴隸制產生關聯,並提供他們機會與製造他們所購買商品的公司進行更深入的對話。奴隸足跡團隊位於加州奧克蘭,致力於透過線上工具,以及線下的社區教育和動員計畫,讓個人、團體和企業了解並採取行動,對抗強迫勞動、人口販運和現代奴隸制。
Stripe 提供一個 API,用於在網路上接受信用卡。Stripe 的 管理介面 最近使用 CoffeeScript 從頭開始重新編寫,並使用 Backbone.js 作為主要架構、Eco 作為範本、Sass 作為樣式表,以及 Stitch 將所有內容打包成 CommonJS 模組。新應用程式直接使用 Stripe 的 API 來執行大部分動作;Backbone.js 模型簡化了將用戶端模型對應到其相對應 RESTful 資源的程序。
Airbnb 在許多產品中使用 Backbone。它始於 Airbnb 行動版網頁(由三人團隊在六週內建成),並已發展成 願望清單、配對、搜尋、社群、付款和內部工具。
SoundCloud 是網路上領先的聲音分享平台,而 Backbone.js 則提供 SoundCloud Mobile 的基礎。此專案使用公開的 SoundCloud API 作為資料來源(透過 nginx 代理傳遞),jQuery 範本 進行呈現,Qunit 和 PhantomJS 進行測試套件。JS 程式碼、範本和 CSS 是使用各種 Node.js 工具(例如 ready.js、Jake、jsdom)建置的,以進行生產部署。Backbone.History 已修改,以支援 HTML5 history.pushState。Backbone.sync 已擴充,並新增一個基於 SessionStorage 的快取層。
Art.sy 是個讓你發現你會喜愛的藝術的地方。Art.sy 是建置在 Rails 上,使用 Grape 提供健全的 JSON API。主網站是一個以 CoffeeScript 撰寫的單一頁面應用程式,並使用 Backbone 在此 API 周圍提供結構。管理員面板和合作夥伴 CMS 也已被擷取到他們自己的 API 使用 Backbone 專案中。
當 Pandora 以 HTML5 重新設計他們的網站時,他們選擇 Backbone.js 來協助管理使用者介面和互動。例如,有一個代表「目前播放曲目」的模型,以及多個檢視會在目前曲目變更時自動更新。電台清單是一個集合,因此當電台新增或變更時,UI 會保持最新狀態。
Inkling 是一種跨平台方式,用來發布互動式學習內容。Inkling for Web 使用 Backbone.js 來製作數百本複雜的書籍(從學生的教科書到旅遊指南和程式設計手冊),在網路上引人入勝且易於取得。Inkling 支援 WebGL 啟用的 3D 圖形、互動式評量、社群分享,以及一個在書中執行練習程式碼的系統,所有這些都在單一頁面 Backbone 驅動的應用程式中。在早期,團隊決定只使用 Backbone.js 和原始 JavaScript,以保持網站輕量化。結果如何?完整的原始程式碼僅重 350kb,且在 iPad、iPhone 和網路用戶端之間具有功能同等性。使用 這段 JavaScript: The Definitive Guide 的摘錄 來試試看。
Code School 課程教授人們各種程式設計主題,例如 CoffeeScript、CSS、Ruby on Rails 等。新的 Code School 課程 挑戰頁面 是從頭開始使用 Backbone.js 建立的,運用其提供的所有功能:路由器、集合、模型和複雜的事件處理。之前,這個頁面是一團亂的 jQuery DOM 處理和手動 Ajax 呼叫。Backbone.js 協助引進一種新的思考方式,用於開發 JavaScript 中的組織化前端應用程式。
CloudApp 是 Mac 的簡易檔案和連結分享工具。Backbone.js 強化了網頁工具,這些工具會使用 文件化 API 來管理 Drops。資料會手動擷取或由 Pusher 推播,並提供給 Mustache 範本進行呈現。查看 附註原始碼,了解其神奇之處。
SeatGeek 的體育場門票地圖最初是使用 Prototype.js 開發的。轉移到 Backbone.js 和 jQuery 協助整理了許多 UI 程式碼,而增加的結構也讓新增功能變得容易許多。SeatGeek 也正在建置一個行動介面,將會從頭到尾使用 Backbone.js。
Easel 是一款瀏覽器內的高保真網頁設計工具,可與您的設計和開發流程整合。Easel 團隊使用 CoffeeScript、Underscore.js 和 Backbone.js 來製作他們的 豐富視覺化編輯器,以及整個網站的其他管理功能。Backbone 的結構讓團隊可以將建置視覺化編輯器的複雜問題分解成可管理的元件,並仍然快速進行。
Jolicloud 是一個開放且獨立的平台和作業系統,提供音樂播放、影片串流、照片瀏覽和文件編輯的功能,將低成本電腦轉變為美觀的雲端裝置。新的 Jolicloud HTML5 應用程式 是使用 Backbone 從頭開始建置的,並與Jolicloud 平台進行通訊,該平台基於 Node.js。Jolicloud 使用 HTML5 AppCache 離線運作,延伸 Backbone.sync 以將資料儲存在 IndexedDB 或 localStorage,並透過 WebSockets 與Joli OS進行通訊。
Salon.io 提供了一個空間,讓攝影師、藝術家和設計師可以自由地在虛擬牆上排列他們的視覺藝術作品。Salon.io 在Rails上執行,但並未使用傳統堆疊的許多部分,因為整個前端被設計成單頁式網路應用程式,使用 Backbone.js、Brunch 和CoffeeScript。
我們的Knight Foundation News Challenge獲獎夥伴MapBox使用 Backbone.js 建立了一個開放原始碼地圖設計工作室:TileMill。TileMill 讓您可以管理基於形狀檔和光柵的地圖圖層,並使用Carto 造型語言直接在瀏覽器中編輯它們的外觀。請注意,華麗的MapBox首頁也是一個 Backbone.js 應用程式。
Blossom 是一個輕量級的專案管理工具,適合精實團隊。Backbone.js 與CoffeeScript大量結合使用,以提供順暢的互動體驗。此應用程式與Brunch一起打包。RESTful 後端使用 Google App Engine 上的Flask建置。
Trello 是一個協作工具,可以將您的專案組織成看板。Trello 看板包含許多卡片清單,其中可以包含核對清單、檔案和對話,並且可以投票並使用標籤進行組織。看板上的更新會即時發生。此網站是使用 Backbone.js 從頭開始建置的,用於所有模型、檢視和路由。
Cristi Balan 和Irina Dumitrascu建立了Tzigla,這是一個協作繪圖應用程式,藝術家可以在其中製作彼此相連的磁磚,以建立超現實繪圖。Backbone 模型有助於組織程式碼,路由器提供可加入書籤的深度連結,而檢視則使用haml.js和Zepto進行呈現。Tzigla 在後端使用 Ruby (Rails) 編寫,在前端使用CoffeeScript編寫,並使用Jammit預先封裝靜態資源。
0.5.3 — 2011 年 8 月 9 日 — 差異 — 文件
檢視的 events 屬性現在可以定義為函式,也可以定義為物件文字,讓以程式方式定義和繼承事件變得更容易。 groupBy 現在從 Underscore 代理為集合的方法。如果伺服器已在載入頁面時將所有內容呈現,請傳遞 Backbone.history.start({silent: true}) 以防止初始路由觸發。修正使用編碼 URL 的 pushState 錯誤。
0.5.2 — 2011 年 7 月 26 日 — 差異 — 文件
bind 函式現在可以接受第三個選用參數,以指定回呼函式的 this。集合中現在允許多個具有相同 id 的模型。修正呼叫 .fetch(jQueryOptions) 可能導致序列化錯誤 URL 的錯誤。修正從 pushState 降級時,在重新導向之前簡短地觸發額外路由。
0.5.1 — 2011 年 7 月 5 日 — 差異 — 文件
0.5.0 版本的清理,簡而言之:改進了從基於雜湊的 URL 到 pushState 的透明升級,反之亦然。修正傳遞給 Model#initialize 的非修改屬性不一致的問題。還原了 0.5.0 的變更,該變更會從路由中移除開頭的 hashbang。新增 contains 作為 includes 的別名。
0.5.0 — 2011 年 7 月 1 日 — Diff — 文件
大量微小的調整和微小的 bug 修復,最好透過查看 提交 diff 來查看。HTML5 pushState 支援,透過使用以下方式選擇加入來啟用:Backbone.history.start({pushState: true})。為了清楚起見,Controller 已重新命名為 Router。Collection#refresh 已重新命名為 Collection#reset,以強調它同時具有使用新模型重設集合,以及在不使用參數時清空集合的能力。saveLocation 已替換為 navigate。RESTful 持久性方法(儲存、擷取等)現在會傳回 jQuery 遞延物件,以進一步成功/錯誤串接和一般便利性。改進 Model#escape 的 XSS 逸出。新增 urlRoot 選項,允許指定 RESTful URL,而不需要使用集合。如果多次呼叫 Backbone.history.start,則會擲回錯誤。Collection#create 現在會在初始化新模型之前進行驗證。view.el 現在可以是 jQuery 字串查詢。Backbone View 現在也可以接受 attributes 參數。Model#defaults 現在可以是函式,也可以是文字屬性物件。
0.3.3 — 2010 年 12 月 1 日 — Diff — 文件
Backbone.js 現在支援 Zepto,與 jQuery 一起,作為 DOM 操作和 Ajax 支援的架構。實作 Model#escape,以有效率地處理用於 HTML 內插的屬性。當嘗試保存模型時,失敗的請求現在會觸發 "error" 事件。普遍的 options 參數現在傳遞為所有 "change" 事件的最後一個參數。
0.3.2 — 2010 年 11 月 23 日 — Diff — 文件
修正 IE7 + 基於 iframe 的「hashchange」事件的 bug。sync 現在可以針對每個模型或每個集合基礎進行覆寫。修正了在 "change" 事件中呼叫 save 時,沒有變更屬性的遞迴錯誤。
0.3.1 — 2010 年 11 月 15 日 — Diff — 文件
所有 "add" 和 "remove" 事件現在都透過模型傳送,以便檢視可以偵聽它們,而不需要知道集合。新增 remove 方法到 Backbone.View。toJSON 不再對 'read' 和 'delete' 請求進行呼叫。Backbone 路由現在能夠載入空的 URL 片段。
0.3.0 — 2010 年 11 月 9 日 — Diff — 文件
Backbone 現在有 控制器 和 歷史記錄,用於根據 URL 片段執行客戶端路由。新增 emulateHTTP,為不執行 PUT 和 DELETE 的舊式伺服器提供支援。新增 emulateJSON,適用於無法接受 application/json 編碼要求的伺服器。新增 Model#clear,用於移除模型中的所有屬性。現在所有 Backbone 類別都可以無縫繼承 CoffeeScript 類別。
0.2.0 — 2010 年 10 月 25 日 — 差異 — 文件
現在,您不必要求伺服器回應在 model 鍵下命名空間,而是可以定義自己的 parse 方法,將回應轉換為模型和集合的屬性。舊的 handleEvents 函式現在稱為 delegateEvents,並會自動作為檢視建構函式的一部分呼叫。新增 toJSON 函式至集合。新增 Underscore 的鏈 至集合。
0.1.2 — 2010 年 10 月 19 日 — 差異 — 文件
新增 Model#fetch 方法,用於從伺服器更新單一模型的屬性。現在可以將 error 回呼傳遞給 set 和 save 作為選項,如果驗證失敗,它將被呼叫,並覆寫 "error" 事件。現在,您可以透過設定 Backbone.emulateHTTP = true,告知 Backbone 使用 _method 駭客手法,而不是 HTTP 方法。現有的模型和集合資料不再會透過 GET 和 DELETE 要求不必要地傳送。新增 rake lint 任務。Backbone 現在已作為 NPM 模組發布。
0.1.1 — 2010 年 10 月 14 日 — 差異 — 文件
新增慣例,如果定義了 initialize 函式,則在執行個體建構時呼叫。文件調整。
0.1.0 — 2010 年 10 月 13 日 — 文件
Backbone 初始版本。