PageRenderTime 14ms CodeModel.GetById 2ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 1ms

/backbone学习笔记.txt

https://github.com/cgg5207/StudyNotes
Plain Text | 612 lines | 509 code | 103 blank | 0 comment | 0 complexity | 539454f56825e75c84d2fff2385fb379 MD5 | raw file
  1Backbone.Events
  2
  3#Events
  4//继承Backbone.Events, 所有对象都有了on 和 trigger, 还可以传参数
  5var object = {};
  6_.extend(object, Backbone.Events);
  7object.on("alert", function(msg) {
  8    alert("Triggered " + msg);
  9});
 10object.trigger("alert", "an event");
 11
 12var dispatcher = _.clone(Backbone.Events); //用这种方式可以把Backbone.Events clone出来,不容易弄乱原来的Class
 13
 14#on object.on(event, callback, [context])
 15object.on("change:title change:author", ...) //可以用空格绑定多个event
 16model.on("change", this.func, this) //要绑定this的话可以在第三个参数放context
 17如果绑定了"all"event的话,那这个对象在trigger任何事件的时候都会trigger这个event
 18还可以这样去绑定多个事件对应多个func
 19model.on({
 20  "change": change,
 21  "help": help
 22});
 23还有只绑定一次的once
 24
 25#off object.off([event], [callback], [context])
 26
 27#listenTo 监听其他对象的事件响应
 28view.listenTo(model, 'change', view.render); 
 29
 30#stopListening object.stopListening([other], [event], [callback]) 
 31
 32#listenToOnce object.listenToOnce(other, event, callback) 
 33
 34#Backbone model 里面的events
 35"add" (model, collection, options) — when a model is added to a collection.
 36"remove" (model, collection, options) — when a model is removed from a collection.
 37"reset" (collection, options) — when the collection's entire contents have been replaced.
 38"sort" (collection, options) — when the collection has been re-sorted.
 39"change" (model, options) — when a model's attributes have changed.
 40"change:[attribute]" (model, value, options) — when a specific attribute has been updated.
 41"destroy" (model, collection, options) — when a model is destroyed.
 42"request" (model, xhr, options) — when a model (or collection) has started a request to the server.
 43"sync" (model, resp, options) — when a model (or collection) has been successfully synced with the server.
 44"error" (model, xhr, options) — when a model's save call fails on the server.
 45"invalid" (model, error, options) — when a model's validation fails on the client.
 46"route:[name]" (params) — Fired by the router when a specific route is matched.
 47"route" (router, route, params) — Fired by history (or router) when any route has been matched.
 48"all" — this special event fires for any triggered event, passing the event name as the first argument.
 49如果在model.set() collection.add()这类方法不想trigger到上面的event,可以传个{slient: true}的参数
 50
 51
 52Backbone.Model
 53example:
 54var Sidebar = Backbone.Model.extend({
 55  promptColor: function() {
 56    var cssColor = prompt("Please enter a CSS color:");
 57    this.set({color: cssColor});
 58  }
 59});
 60window.sidebar = new Sidebar;
 61sidebar.on('change:color', function(model, color) { //属性改变后的function
 62  $('#sidebar').css({background: color});
 63});
 64sidebar.set({color: 'white'});
 65sidebar.promptColor();
 66
 67#extend
 68var Note = Backbone.Model.extend({
 69  initialize: function() { ...  },
 70  author: function() { ...  },
 71  coordinates: function() { ...  },
 72  allowedToEdit: function(account) {
 73    return true;
 74  }
 75});
 76
 77var PrivateNote = Note.extend({  //可以继承自己创建的Model
 78  allowedToEdit: function(account) {
 79    return account.owns(this);
 80  }
 81});
 82
 83如果继承的时候要用super,覆写方法的话,要明确指定方法路径
 84var Note = Backbone.Model.extend({
 85  set: function(attributes, options) {
 86    Backbone.Model.prototype.set.apply(this, arguments);
 87  }
 88});
 89
 90#constructor /intialize
 91要设定实例变量,直接在new的时候传入即可,Model里面的intialize方法就是构造函数
 92{url: "...."} {urlRoot: "....."}可以自己定义model的restful URL
 93
 94#get
 95model.get("fuck") //model里面get属性
 96
 97#set
 98model.set({fuck: "fuck you"}) //set 属性
 99会trigger model的"change"事件,还会trigger详细到 "change:fuck" 这个事件
100
101#escape 类似get(), 但会把属性转义成html可显示的内容,例如<>这些符号
102
103#has(attribute) 判断model里面的attribute是不是空或undefined
104
105#unset 会把某个attribute直接移除出model attributes hash, trigger "change"
106
107#clear 全部attribute清掉
108
109#id 默认有的属性,如果自己设的attributes里面也包含这个id属性,则会把原来id的内容拷过去
110
111#idAttribute,方便指定哪一个key属性作为id,例如nosql里面的mongoid的id是_id
112var Meal = Backbone.Model.extend({
113    idAttribute: "_id"
114});
115var cake = new Meal({ _id: 1, name: "Cake"  });
116alert("Cake id: " + cake.id);
117
118#cid 这个东西跟spine的一样,就是model未保存时,还在内存或者storage里面时用得client_id
119
120#attributes 返回所有属性的一个hash
121
122#changed 返回最后一个trigger过的changed 的属性hash
123
124#defaults 用于在model创建时设定一堆默认属性和值
125var Meal = Backbone.Model.extend({
126  defaults: {
127    "appetizer":  "caesar salad",
128    "entree":     "ravioli",
129    "dessert":    "cheesecake"
130  }
131});
132alert("Dessert will be " + (new Meal).get('dessert'));
133
134#toJSON
135var artist = new Backbone.Model({
136    firstName: "Wassily",
137    lastName: "Kandinsky"
138});
139artist.set({birthday: "December 16, 1866"});
140alert(JSON.stringify(artist)); //本来只是返回一个json object, 最好用JSON.stringify去变成json string
141
142#sync model.sync(method, model, [options]) //用于持久化同步
143
144#fetch 比spine可定制强很多,返回一个jqXHR对象,可以接受success或error的callback, 参数是(model, response, options)
145
146#save model.save([attributes], [options]) 
147如果用ajax,成功的话返回一个jqXHR, 失败的话返回false, 如果model isNew,就create, otherwise update
148options hash里面可以直接传{success:function(model, xhr, options){}} 这样直接可以第一时间得到返回来的东西
149如果想只想更新了更新的部分可以model.save(attrs,{patch: true}), 这样会有一个PATCH请求动作给HTTP
150!! model.save(attrs, {wate: true}),等服务器保存完才把model设值,这样可以保证数据绝对同步
151
152关于事件,save成功后会trigger "change", ajax 刚开时的时候会 trigger "request", 这个很有用可以给用户提示, ajax完成后会有个 "sync"事件
153
154一个例子:
155Backbone.sync = function(method, model) {
156  alert(method + ": " + JSON.stringify(model));
157  model.id = 1;
158};
159
160var book = new Backbone.Model({
161  title: "The Rough Riders",
162  author: "Theodore Roosevelt"
163});
164book.save();
165book.save({author: "Teddy"});
166
167#destroy
168事件和调用方式基本类似save()
169
170#包含underscore 的几个方法
171keys
172values
173pairs
174invert
175pick
176omit
177user.pick('first_name', 'last_name', 'email');
178chapters.keys().join(', ');
179
180#validate
181在save之前触发, validate不通过时会trigger "invalid", 然后model.validationError 会得到错误的信息
182var Chapter = Backbone.Model.extend({
183  validate: function(attrs, options) {
184    if (attrs.end < attrs.start) {
185      return "can't end before it starts";
186    }
187  }
188});
189var one = new Chapter({
190  title : "Chapter One: The Beginning"
191});
192one.on("invalid", function(model, error) {
193  alert(model.get("title") + " " + error);
194});
195one.save({
196  start: 15,
197  end:   10
198});
199
200#validationError 上面写了
201
202#isValid 判断model是不是valid
203
204#url model.url()
205可以用urlRoot去设定,或直接在model初始化的时候设个url属性
206
207#urlRoot
208如果你的model不是在collection里头的, 就需要设定一下urlRoot属性
209var Book = Backbone.Model.extend({urlRoot : '/books'});
210var solaris = new Book({id: "1083-lem-solaris"});
211alert(solaris.url());
212
213#parse
214返回一个 raw response对象,会在fetch或save的时候调用,可以覆写他
215
216#clone
217返回model的克隆
218
219#isNew()
220未在服务器保存的就是true
221
222#hasChanged
223上一次"change"事件后有无发生变化
224
225#previous model.previous(attribute)
226在"change"事件中,可以获取上一次"change"时候的属性
227var bill = new Backbone.Model({
228    name: "Bill Smith"
229});
230bill.on("change:name", function(model, name) {
231    alert("Changed name from " + bill.previous("name") + " to " + name);
232});
233bill.set({name : "Bill Jones"});
234
235#previousAttributes
236
237
238Backbone.Collection
239在collection下面的所有model "change"的话都会trigger collection的"change", 还有 "add", "remove"等事件, model里面的所有属性事件发生,都会在collection里面trigger多一份 documents.on("change:selected", ...)
240
241#extend
242
243#model
244设这个方法可以快速设定下属的model
245var Library = Backbone.Collection.extend({
246    model: Book
247});
248还可以多态式添加model
249var Library = Backbone.Collection.extend({
250  model: function(attrs, options) {
251    if (condition) {
252            return new PublicDocument(attrs, options);
253    } else {
254            return new PrivateDocument(attrs, options);
255    }
256  }
257});
258
259#初始化,可以在初始化的时候就扔进model实例,或者只设定model的class
260var tabs = new TabSet([tab1, tab2, tab3]);
261var spaces = new Backbone.Collection([], {
262    model: Space,
263    url: '/spaces'
264});
265
266#models 返回所有model的array
267
268#toJSON 返回array JSON
269
270#sync 类似model
271
272#underscore method
273forEach (each)
274map (collect)
275reduce (foldl, inject)
276reduceRight (foldr)
277find (detect)
278filter (select)
279reject
280every (all)
281some (any)
282contains (include)
283invoke
284max
285min
286sortBy
287groupBy
288sortedIndex
289shuffle
290toArray
291size
292first (head, take)
293initial
294rest (tail)
295last
296without
297indexOf
298lastIndexOf
299isEmpty
300chain
301
302books.each(function(book) {
303    book.publish();
304});
305var titles = books.map(function(book) {
306    return book.get("title");
307});
308var publishedBooks = books.filter(function(book) {
309    return book.get("published") === true;
310});
311var alphabetical = books.sortBy(function(book) {
312    return book.author.get("name").toLowerCase();
313});
314
315#add collection.add(models, [options]) 
316如果options传个{at: index} 的话,model就会加到响应的位置, 这个在排序的情况下十分好用, 一般collection里面已有的model, 再add进来的话就会被忽略,但是可以给个{merge: true}就可以实现merge, 更新model的属性
317var ships = new Backbone.Collection;
318ships.on("add", function(ship) {
319  alert("Ahoy " + ship.get("name") + "!");
320
321});
322ships.add([
323  {name: "Flying Dutchman"},
324  {name: "Black Pearl"}
325]);
326
327#remove collection.remove(models, [options]) 
328trigger "remove", 可以给个 slient: true 去不trigger
329
330#reset collection.reset([models], [options]) 
331重设collection里面的所有model, 会trigger "reset", 在事件响应的options里面,options.previousModels可以拿到之前的所有model
332在页面onload的时候把整个accounts的collection重设一下
333<script>
334  var accounts = new Backbone.Collection;
335  accounts.reset(<%= @accounts.to_json %>);
336</script>
337
338#set collection.set(models, [options]) 
339model未在集合里时,会create; 在的时候,会update(merge: true), 会响应响应"remove", "add" , "change"的事件,可以细致定义到{remove: false} {add: false} {merge: false}
340var vanHalen = new Collection([eddie, alex, stone, roth]);
341vanHalen.set([eddie, alex, stone, hagar]);
342// Fires a "remove" event for roth, and an "add" event for "hagar".
343// // Updates any of stone, alex, and eddie's attributes that may have
344// // changed over the years.
345
346#get collection.get(id)
347从id或cid里那model
348
349#at collection.at(index)
350拿到某个位置的model
351
352#push
353在collection最后加model
354
355#unshift
356在头部add一个
357
358#shift
359删除头部的model
360
361#length
362
363#comparator collection.comparator
364主要给sortBy功能提供支持
365var Chapter  = Backbone.Model;
366var chapters = new Backbone.Collection;
367chapters.comparator = function(chapter) {
368    return chapter.get("page");
369};
370chapters.add(new Chapter({page: 9, title: "The End"}));
371chapters.add(new Chapter({page: 5, title: "The Middle"}));
372chapters.add(new Chapter({page: 1, title: "The Beginning"}));
373alert(chapters.pluck('title'));
374
375#sort
376trigger "sort"
377
378#pluck
379
380#where
381var friends = new Backbone.Collection([
382    {name: "Athos",      job: "Musketeer"},
383    {name: "Porthos",    job: "Musketeer"},
384    {name: "Aramis",     job: "Musketeer"},
385    {name: "d'Artagnan", job: "Guard"},
386]);
387var musketeers = friends.where({job: "Musketeer"});
388alert(musketeers.length);
389
390#findWhere
391和where区别就是只返回匹配到的第一个
392
393#url
394var Notes = Backbone.Collection.extend({
395    url: '/notes'
396});
397// Or, something more sophisticated:
398var Notes = Backbone.Collection.extend({
399 url: function() {
400     return this.document.url() + '/notes';
401       }
402       });
403 }
404});
405
406#parse 类似model
407
408#clone
409
410#fetch
411这个比model多了就是可以pass jqery.ajax data, 可以分页
412documents.fetch({data: {page: 3}})
413
414#create
415响应事件顺序, "add" , "request" , "sync"
416var Library = Backbone.Collection.extend({
417    model: Book
418});
419var nypl = new Library;
420var othello = nypl.create({
421    title: "Othello",
422    author: "William Shakespeare"
423});
424
425Backbone.Router
426路由都创建成功后记得运行Backbone.history.start() or Backbone.history.start({pushState: true})
427创建example
428var Workspace = Backbone.Router.extend({
429  routes: {
430    "help":                 "help",    // #help
431    "search/:query":        "search",  // #search/kiwis
432    "search/:query/p:page": "search"   // #search/kiwis/p7
433  },
434  help: function() {
435    ...
436  },
437  search: function(query, page) {
438    ...
439  }
440})
441
442#route router.route(route, name, [callback])
443
444#navigate router.navigate(fragment, [options]) 
445用于更新路由的url, 如果想同时触发路由,options传个trigger: true
446openPage: function(pageNumber) {
447  this.document.pages.at(pageNumber).open();
448  this.navigate("page/" + pageNumber);
449}
450app.navigate("help/troubleshooting", {trigger: true});
451app.navigate("help/troubleshooting", {trigger: true, replace: true});
452
453Backbone.history
454backbone的pushState可以帮你自动识别好是否支持pushState浏览器问题, 用start()方法去检测浏览器hashchange 事件
455$(function(){
456  new WorkspaceRouter();
457  new HelpPaneRouter();
458  Backbone.history.start({pushState: true});
459});
460
461Backbone.sync 就只是一个jqueryAjax的包装
462#sync sync(method, model, [options])
463
464Backbone.View
465var DocumentRow = Backbone.View.extend({
466  tagName: "li",
467  className: "document-row",
468  events: {
469    "click .icon":          "open",
470    "click .button.edit":   "openEditDialog",
471    "click .button.delete": "destroy"
472  },
473  initialize: function() {
474    this.listenTo(this.model, "change", this.render);
475  }
476  render: function() {
477    ...
478  }
479});
480创建的时候传入的参数会在实例变量 @options里面
481
482# view.el
483类似spine的el, 但是backbone在你初始化时如果指定好tagName, id, className, backbone会自动帮你定义好el
484
485# view.$el
486很方便的el cache,可以读回之前的dom避免次次重新运算一次
487view.$el.show();
488listView.$el.append(itemView.el);
489
490#delegateEvents 主要是用jquery的on
491可以在events上轻松定义
492var DocumentView = Backbone.View.extend({
493  events: {
494    "dblclick"                : "open",
495    "click .icon.doc"         : "select",
496    "contextmenu .icon.doc"   : "showMenu",
497    "click .show_notes"       : "toggleNotes",
498    "click .title .lock"      : "editAccessLevel",
499    "mouseover .title .date"  : "showTooltip"
500  },
501  render: function() {
502    this.$el.html(this.template(this.model.attributes));
503    return this;
504  },
505  open: function() {
506    window.open(this.model.get("viewer_url"));
507  },
508  select: function() {
509    this.model.set({selected: true});
510  },
511});
512
513Backbone.LocalStoreage
514var TodoList = Backbone.Collection.extend({
515  model: Todo,
516  localStorage: new Backbone.LocalStorage("todos-backbone")
517});
518
519##### ModelBinder #####
520https://github.com/theironcook/Backbone.ModelBinder
521作用是可以方便绑定model的attribute到 html element, 只要html标签里面有name="xxx", 绑定后更新model属性,这个标签的内容也会跟着更改
522三个public方法
523constructor
524bind(model, rootEl, bindings)
525unbind();
526
527//////例子1 
528Welcome, <span name="firstName"></span>
529
530Edit your information:
531<input type="text" name="firstName"/>
532
533SomeView = Backbone.View.extend({
534  render: function(){
535    this.modelBinder.bind(this.model, this.el);
536  }
537});
538
539这里绑定好firstName到model, input里面改变了, 上面的span也会修改
540//////////例子2
541<input type="text" name="homeAddress"/>
542<input type="text" name="workAddress "/>
543var bindings = {homeAddress: '[name=homeAddress]', workAddress : '[name=workAddress ]'};
544modelBinder.bind(this.model, this.el, bindings);
545第三个参数bindings示例,可以同时绑定多个attribute, 当然除了name=xxx这种选择器,还可以使用#id这种jquery选择器
546还可以这样
547 <input type="text" class="myTestClass" name="address"/> myTestAttribute: '[class~=myTestClass]'
548
549bindings参数还可以放个converter,这个converter要求是个function,可以让你自定义如何格式化值
550var phoneConverter = function(direction, value){
551   // direction is either ModelToView or ViewToModel
552   // Return either a formatted value for the view or an un-formatted value for the model
553};
554
555var bindings = {phoneNumber: {selector: '[name=phoneNumber]', converter: phoneConverter}}
556modelBinder.bind(this.model, this.el, bindings );
557A converter function is passed 4 parameters.
558Direction - either ModelToView or ViewToModel
559Value - the model's attribute value or the view element's value
560Attribute Name
561Model - this is more useful when you're dealing with calculated attributes
562
563#给每个collection的model加属性
564pages = new PagesCollection()
565pages.fetch()
566pages.invoke("set", {h: 123})
567然后每一个page都可以 page.get("h")
568
569--------------------------
570Eckbone.EventBinder();
571
572var model = new MyModel();
573
574var handler = {
575    doIt: function(){ /* ... */  }
576
577}
578// same args list as model.on, but putting the model as the first parameter
579binder.bindTo(model, "change:foo", handler.doIt, handler) 第四个参数是callback的context
580
581所以以后注意路由要这样写, 添加一个appView去决定切换的时候把前一个view close掉
582function AppView(){
583  this.showView(view) {
584    if (this.currentView){
585      this.currentView.close();
586    }
587    this.currentView = view;
588    this.currentView.render();
589    $("#mainContent").html(this.currentView.el);
590  }
591}
592
593MyRouter = Backbone.Router.extend({
594  routes: {
595    "": "home",
596    "post/:id": "showPost"
597  },
598  initialize: function(options){
599    this.appView = options.appView;
600  },
601  home: function(){
602    var homeView = new HomeView();
603    this.appView.showView(homeView);
604
605  },
606  showPost: function(id){
607    var post = posts.get(id);
608    var postView = new PostView({model: post});
609    this.appView.showView(postView);
610  }
611});
612