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
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
// 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])
onceobject.once(event, callback, [context])
listenToobject.listenTo(other, event, callback)
view.listenTo(model, 'change', view.render);
stopListeningobject.stopListening([other], [event], [callback])
view.stopListening();view.stopListening(model);
listenToOnceobject.listenToOnce(other, event, 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(模型)被时触发。
- "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(模型)在客户端 失败时触发。
- "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.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])
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])
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的。否则model.collection 这个属性会在你第一次添加model到一个collection的时候被自动添加。 需要注意的是相反的是不正确的,因为传递这个选项给构造函数将不会自动添加model到集合。有时这个是很有用的。
如果{parse: true}被作为一个option选项传递, attributes将在 到model之前首先通过被转换。
getmodel.get(attribute)
setmodel.set(attributes, [options])
note.set({title: "March 20", content: "In his eyes she eclipses..."});book.set("title", "A Scandal in Bohemia");
escapemodel.escape(attribute)
var hacker = new Backbone.Model({ name: ""});alert(hacker.escape('name'));
hasmodel.has(attribute)
if (note.has("title")) { ...}
unsetmodel.unset(attribute, [options])
clearmodel.clear([options])
idmodel.id
idAttributemodel.idAttribute
var Meal = Backbone.Model.extend({ idAttribute: "_id"});var cake = new Meal({ _id: 1, name: "Cake" });alert("Cake id: " + cake.id);
cidmodel.cid
attributesmodel.attributes
建议采用 更新 attributes而不要直接修改。 如果您想检索和获取模型属性的副本, 用 _.clone(model.attributes) 取而代之。
由于这样的事实: 接受空格分隔事件列表, 但是属性名称不应该包括空格。
changedmodel.changed
defaultsmodel.defaults or model.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])
var artist = new Backbone.Model({ firstName: "Wassily", lastName: "Kandinsky"});artist.set({birthday: "December 16, 1866"});alert(JSON.stringify(artist));
syncmodel.sync(method, model, [options])
fetchmodel.fetch([options])
// 每隔 10 秒从服务器拉取数据以保持频道模型是最新的setInterval(function() { channel.fetch();}, 10000);
savemodel.save([attributes], [options])
相反,如果你只想将改变属性发送到服务器, 调用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 支持在选项散列表中传入 success 和 error 回调函数, 回调函数支持传入(model, response, options) 作为参数。 如果服务端验证失败,返回非 200 的 HTTP 响应码,将产生文本或 JSON 的错误内容。
book.save("author", "F.D.R.", {error: function(){ ... }});
destroymodel.destroy([options])
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)
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
isValidmodel.isValid()
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 时,是否存在 属性。 例如,一个 id 为 101 的模型,存储在 url 为 "/documents/7/notes" 的 中, 那么该模型的 URL 为:"/documents/7/notes/101"
urlRootmodel.urlRoot or model.urlRoot()
var Book = Backbone.Model.extend({urlRoot : '/books'});var solaris = new Book({id: "1083-lem-solaris"});alert(solaris.url());
parsemodel.parse(response, options)
如果使用的3.1版本之前的 Rails 后端,需要注意 Rails's 默认的 to_json 实现已经包含了命名空间之下的模型属性。 对于无缝的后端集成环境禁用这种行为:
ActiveRecord::Base.include_root_in_json = false
clonemodel.clone()
isNewmodel.isNew()
hasChangedmodel.hasChanged([attribute])
注意,本方法以及接下来 change 相关的方法,仅对 "change"事件发生有效。
book.on("change", function() { if (book.hasChanged("title")) { ... }});
changedAttributesmodel.changedAttributes([attributes])
previousmodel.previous(attribute)
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" 事件, 从服务器更新,并能使用 提供的方法。
集合中的模型触发的任何事件都可以在集合身上直接触发,所以我们可以监听集合中模型的变化: documents.on("change:selected", ...)
extendBackbone.Collection.extend(properties, [classProperties])
modelcollection.model
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])
var tabs = new TabSet([tab1, tab2, tab3]);var spaces = new Backbone.Collection([], { model: Space});
modelscollection.models
toJSONcollection.toJSON([options])
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])
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])
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])
resetcollection.reset([models], [options])
下面是一个例子 使用reset来引导一个集合在页面初始化时加载, 在Rails应用程序中:
调用collection.reset(),不传递任何模型作为参数 将清空整个集合。
setcollection.set(models, [options])
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)
var book = library.get(110);
atcollection.at(index)
pushcollection.push(model, [options])
popcollection.pop([options])
unshiftcollection.unshift(model, [options])
shiftcollection.shift([options])
slicecollection.slice(begin, end)
lengthcollection.length
comparatorcollection.comparator
"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])
pluckcollection.pluck(attribute)
var stooges = new Backbone.Collection([ {name: "Curly"}, {name: "Larry"}, {name: "Moe"}]);var names = stooges.pluck("name");alert(JSON.stringify(names));
wherecollection.where(attributes)
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)
urlcollection.url or collection.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)
var Tweets = Backbone.Collection.extend({ // The Twitter Search API returns tweets under "results". parse: function(response) { return response.results; }});
clonecollection.clone()
fetchcollection.fetch([options])
Backbone.sync = function(method, model) { alert(method + ": " + model.url);};var accounts = new Backbone.Collection;accounts.url = '/accounts';accounts.fetch();
fetch行为可以通过使用有效的选项进行定制。 例如,要获取一个集合,每一个新的模型会得到一个 "add"事件,和每改变现有的模型的 "change"事件, 不删除任何东西:collection.fetch({remove: false})
jQuery.ajax选项也可以直接传递作为 fetch选项, 所以要获取一个分页集合的特定页面使用:Documents.fetch({data: {page: 3}})。
需要注意的是 fetch 不应该被用来在页面加载完毕时填充集合数据 — 所有页面初始数据应当在 时已经就绪。 fetch 适用于惰性加载不需立刻展现的模型数据:例如:例如文档中 可切换打开和关闭的选项卡内容。
createcollection.create(attributes, [options])
创建一个模型将立即触发集合上的"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])
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
举个例子,路由 "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的一部分, 访问时会被(正确地)当作一个独立的路由。 docs和 docs/将触发不同的回调。 如果你不能避免产生这两种类型的URLs时, 你可以定义一个"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) { ...});
constructor / initializenew Router([options])
routerouter.route(route, name, [callback])
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])
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)
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])
需要指出的是,如果想在应用中使用 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 请求,并且返回一个 。 如果想采用不同的持久化方案,比如 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" 请求从服务器端响应一个集合()时,便拆解模型属性对象的数组。
当一个模型或集合开始 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 => accountend
一个技巧: 通过设置ActiveRecord::Base.include_root_in_json = false,在模型上禁用默认命名空间的to_json来整合 Rails 3.1之前的版本, 。
ajaxBackbone.ajax = function(request) { ... };
emulateHTTPBackbone.emulateHTTP = true
Backbone.emulateHTTP = true;model.save(); // POST to "/collection/id", with "_method=PUT" + header.
emulateJSONBackbone.emulateJSON = true
Backbone.View(视图)
Backbone 视图几乎约定比他们的代码多 — 他们并不限定你的HTML或CSS, 并可以配合使用任何JavaScript模板库。 一般是组织您的接口转换成逻辑视图, 通过模型的支持, 模型变化时, 每一个都可以独立地进行更新, 而不必重新绘制该页面。我们再也不必钻进 JSON 对象中,查找 DOM 元素,手动更新 HTML 了,通过绑定视图的 render 函数到模型的 "change" 事件 — 模型数据会即时的显示在 UI 中。
extendBackbone.View.extend(properties, [classProperties])
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])
var doc = documents.first();new DocumentRow({ model: doc, id: "document-row-" + doc.id});
elview.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
view.$el.show();listView.$el.append(itemView.el);
setElementview.setElement(element)
attributesview.attributes
$ (jQuery)view.$(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])
var LibraryView = Backbone.View.extend({ template: _.template(...)});
renderview.render()
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 模板引擎。 , , 和 都是很好的选择。 因为已经引入页面了,如果你喜欢简单的插入JavaScript的样式模板。 可以使用并是一个很好的选择。
无论基于什么考虑,都永远不要在 Javascript 中拼接 HTML 字符串。 在DocumentCloud中, 我们使用来打包JavaScript模板,并存储在/app/views中,作为我们主要的core.js包的一部分。
removeview.remove()
delegateEventsdelegateEvents([events])
events 属性也可以被定义成返回 events 对象的函数,这样让我们定义事件,以及实现事件的继承变得更加方便。
视图 期间使用 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()
Utility(实用功能)
Backbone.noConflictvar backbone = Backbone.noConflict();
var localBackbone = Backbone.noConflict();var model = localBackbone.Model.extend(...);
Backbone.$Backbone.$ = $;
var Backbone.$ = require('jquery');