1.backbone 是个mvc的库,官方文档说它是个库,而不是个框架。库和框架的区别就是,库只是个工具,方便你的项目应用,不会改变你的项目结构,而框架会有一套自己的机制,项目需要遵循框架的设计来实现,你要适应框架。backbone 可以当作库或者框架来用都可以。当作库,你可以只使用它的部分特性,如事件;当作框架的话,可以使用它的完整的mvc,router,history。
2.backbone的优点:a.实现了mvc结构,虽然controller里面只有router。b.可以通过事件监听,自动刷新view
backbone的缺点:a.所有的业务逻辑都在view里,view太重;b.锚点路由不利于seo
3.backbone的model,通过Backbone.sync来代理和服务器交互。也可以重写方法,把数据放到其它地方。
4.collection 也使用Backbone.sync 将一个集合状态持久化到服务器。
重写Backbone.sync 来完成自定义处理;参考ackbone.localStorage.js
Backbone.sync=function(method,model){ alert(""+method+":"+model.url); } var list=new Backbone.Collection(); list.url="/search"; list.fetch();
可以监听集合chang事件,集合中模型发生变化都会出发change事件
5.model和collection 都集成了undercore的部分方法,方便操作
6.事件:
a.如果你的一个页面含有大量的不同事件,我们约定使用冒号来为事件添加 命名空间 俗成地使用冒号来命名:"poll:start", 或 "change:selection"
//sample1 var obj={}; _.extend(obj,Backbone.Events); obj.on("myEvt:first",function(e){ alert("hi,and data is "+e.data); }); obj.on("myEvt:second",function(e){ alert("hi,and data is "+e.data); }); obj.trigger("myEvt:first",{data:"first"}); obj.trigger("myEvt:second",{data:"second"});
//sample2 var obj={}; _.extend(obj,Backbone.Events); obj.on("all",function(e,data){ console.log("hi,and data is "+data); }); obj.trigger("myEvt:first","first"); obj.trigger("myEvt:second","second"); obj.trigger("test","test");
b.让 object 监听 另一个(other)对象上的一个特定事件。object.listenTo(other, event, callback)
而使用这种形式的优点是:listenTo允许 object来跟踪这个特定事件,并且以后可以一次性全部移除它们。
callback 在object上下文中执行
view.listenTo(model, 'change', view.render);
结束监听事件
view.stopListening(model);
c.change:[attribute]" (model, value, options) — 当一个model(模型)的某个特定属性被更新时触发
"change:[命名空间]" 和 change:[attribute] 的区别:
"change:[命名空间]" 只是"事件:[命名空间]"的一个特例,既可以是change事件,也可以是其它事件,包括自定义事件。需要手动触发。
change:[attribute] 它会关联model的属性,当一个model(模型)的某个特定属性被更新时触发
//change:[attribute] sample: var model=new Backbone.Model({title:'天猫',name:'商城'}); model.on('change:title',function(e){ // console.log('title changed',JSON.stringify(e)); alert('title changed:'+JSON.stringify(e)); }) model.set({title:'京东'});
//change:[命名空间] sample: var obj={}; _.extend(obj,Backbone.Events); obj.on("myEvt:first",function(e){ alert("hi,and data is "+e.data); }); obj.on("myEvt:second",function(e){ alert("hi,and data is "+e.data); }); obj.trigger("myEvt:first",{data:"first"}); obj.trigger("myEvt:second",{data:"second"});
7.
Backbone.sync 是backbone数据持久化的函数接口,用于读取和保存数据。默认情况下,它使用 jQuery.ajax 方法发送 RESTful json 请求,并且返回一个 jqXHR。 如果想采用不同的持久化方案,比如 WebSockets, XML, 或 Local Storage,我们可以重载该函数。
sync(method, model, [options])
默认 sync 映射 REST 风格的 CRUD 类似下面这样:
create → POST /collection
read → GET /collection[/id]
update → PUT /collection/id
patch → PATCH /collection/id
delete → DELETE /collection/id
model.fetch/model.save/model.destory 会通过Backbone.sync操作持久化的数据
collection.fetch/collection.create 会通过Backbone.sync操作持久化的数据
//sample 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();//create: {"title":"The Rough Riders","author":"Theodore Roosevelt"} book.save({author: "Teddy"});//update: {"title":"The Rough Riders","author":"Teddy","id":1}
8.todo sample 分析
a.默认情况下,添加一个新的记录,会先触发model add event, 然后才会触发Backbone.sync的方法。
input new item and click enter -> collection.create->trigger collection add event -> Backbone.sync ('create')->new Store() ('create') -> localStorage.setItem()
b.可以通过设置,{wait: true} , 先触发Backbone.sync方法,然后在触发model add event. 例如:app.list.create(this.newAttributes(),{wait: true});
todo sample完整代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1"> <style type="text/css"> #todoapp ul { list-style-type: none; list-style-type: none; /* Hides bullet points from todo list */ } #todo-list input.edit { display: none; /* Hides input box*/ } #todo-list .editing label { display: none; /* Hides label text when .editing*/ } #todo-list .editing input.edit { display: inline; /* Shows input text box when .editing*/ } </style> </head> <body> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script> <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script> <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/backbone-localstorage.js/1.0/backbone.localStorage-min.js"></script> <!-- <script type="text/javascript" src="backbone-localstorage.js"></script> --> <section id="todoapp"> <header id="header"> <h1>Todos</h1> <input id="new-todo" placeholder="What needs to be done?" autofocus> <div> <a href="#/">show all</a> | <a href="#/pending">show pending</a> | <a href="#/completed">show completed</a> </div> </header> <section id="main"> <ul id="todo-list"></ul> </section> </section> <!-- Templates --> <script type="text/template" id="item-template"> <div class="view"> <input class="toggle" type="checkbox" <%= completed?'checked':'' %> /> <label><%= title %></label> <input class="edit" value="<%- title %>"> <button class="destroy">remove</button> </div> </script> <script type="text/javascript"> var app={}; app.myModel=Backbone.Model.extend({ default:{ title:"", completed:false }, toggle: function(){ this.save({ completed: !this.get('completed')}); } }); app.modelList=Backbone.Collection.extend({ model:app.myModel, localStorage:new Store("backbone-todo"), completed: function() { return this.filter(function( todo ) { return todo.get('completed'); }); }, remaining: function() { return this.without.apply( this, this.completed() ); } }); app.list=new app.modelList(); app.liview=Backbone.View.extend({ tagName:"li", tpl:_.template($("#item-template").html()), render:function(){ this.$el.html(this.tpl(this.model.toJSON())); this.input=$(".edit"); return this; }, initialize: function(){ this.model.on('change', this.render, this); this.model.on('destroy', this.remove, this); }, events: { 'click label' : 'edit', 'keypress .edit' : 'updateOnEnter', 'blur .edit' : 'close', 'click .toggle': 'toggleCompleted', 'click .destroy': 'destroy' }, edit: function(){ this.$el.addClass('editing'); this.input.focus(); }, close: function(){ var value = this.input.val().trim(); if(value) { this.model.save({title: value}); } this.$el.removeClass('editing'); }, toggleCompleted: function(){ this.model.toggle(); }, updateOnEnter: function(e){ if(e.which == 13){ this.close(); } }, destroy:function(){ this.model.destroy(); } }) app.view=Backbone.View.extend({ el:"#todoapp", initialize:function(){ this.input=$("#new-todo"); app.list.on("add",this.addAll,this); app.list.on("reset",this.addAll,this); app.list.fetch();//拉取数据 }, addAll:function(){ $("#todo-list").html(''); app.list.each(this.addOne,this); }, addOne:function(md){ var li=new app.liview({model:md}); $("#todo-list").append(li.render().el); }, events: { 'keypress #new-todo': 'createTodoOnEnter' }, createTodoOnEnter:function(e){ if ( e.which !== 13 || !this.input.val().trim() ) { return; } app.list.create(this.newAttributes(),{wait: true});//,{wait: true} this.input.val(''); // clean input box }, newAttributes: function(){ return { title: this.input.val().trim(), completed: false } } }); app.myRouter=Backbone.Router.extend({ routes:{ "":"index", "search":"search", "search/:id":"search" }, index:function(){ console.log("this is home page."); Backbone.history.stop(); }, search:function(id){ console.log("this is search page. And param is "+id); } }); app.router=new app.myRouter(); var helloView=new app.view(); Backbone.history.start(); </script> </body> </html>
//1.collection.add(model) //collection.add -> collection.set -> model.trigger("add") -> triggerEvents -> (ev = events[i]).callback.call(ev.ctx, a1, a2, a3) //2.listenTo //A.listenTo(B,'click',callback) -> B.on('click',callback,A);