随着JavaScript程序变得愈来愈复杂,每每须要一个团队协做开发,这时代码的模块化和组织规范就变得异常重要了。MVC模式就是代码组织的经典模式。backbone.js就是为前端开发提供MVC模式滴!css
官网左侧菜单栏里面就是backbone.js的所有模块了html
在使用backbone.js的时候,必须引入underscore.js。
此外在官网上面都会给出代码示例,在代码的右上角上,有一个运行的按钮,点击的运行就能够看到这段代码运行的结果啦。前端
因为网页编程不一样于客户端编程,在MVC的基础上,JavaScript社区产生了各类变体框架MVP(Model-View-Presenter)、MVVM(Model-View-ViewModel)等等,有人就把全部这一类框架的各类模式统称为MV*。ajax
框架的优势在于合理组织代码、便于团队合做和将来的维护,缺点在于有必定的学习成本,且限制你只能采起它的写法。数据库
$(function(){ var User = Backbone.Model.extend({ defaults : { name : 'tom' } }); var View = Backbone.View.extend({ initialize : function(){ console.log("initialize"); this.listenTo( this.model , 'change' , this.show ); // 当与这个view绑定的model数据发生变化的时候,调用show方法 }, show : function(model){ // 向页面中输出信息 $('body').append( '<div>'+ this.model.get('name')+ '</br>也能够经过参数调用</br>' + model.get('name') +'</div>' ); } }); var tom = new User; var view = new View({model:tom}); // 建立view实体 setTimeout(function(){ tom.set('name','jack'); // 修改数据 }, 1000); // 一秒后修改数据,触发show });
listenTo容许一个对象监听另外一个对象的事件,上面的代码就是让view监听model的change事件,而后调用show()
方法编程
var tom = new Backbone.Model({'name':'tom'}); // 建立学生tom var peter = new Backbone.Model({'name':'peter'}); // 建立学生peter var students = new Backbone.Collection(); // tom和peter都是学生 students.add( tom ); // 向Collection中添加学生 students.add( peter ); console.log( JSON.stringify(students) ); //[{"name":"tom"},{"name":"peter"}]
用new的方式建立了两个Model的实例;经过json对象传参方式给Model的constuctor构造函数传递了name属性。
用new的方式建立了一个Collection实例;调用students的add方法,将tom和peter添加到集合中。
在文档中能够看出,使用{'name':'tom'}
这种方式给Model设置的属性,实际上会调用model.set()方法。json
var User = Backbone.Model.extend({ sayHello : function(){ //实例方法 console.log("hello"); } }, { sayWorld : function(){ //静态方法 console.log("world"); } }); var tom = new User; // 建立一个用户 tom.sayHello(); // 调用用户的实例方法 User.sayWorld(); // 直接调用Model的静态方法
使用extend扩展Backbone.Model,第一个参数是实例对象中的属性,第二个可选的参数会直接注册到构造函数成为静态方法。这样即便没有实例化对象,也能调用Model中定义的方法浏览器
var User = Backbone.Model.extend({ defaults : { // 默认属性,可是子类也会继承 "name": "tom" }, sayHello : function(){ // 父类的方法 console.log("hello"); } }); var ChildUser = User.extend({ // ChildUser 继承自User sayChild : function(){ // 子类的方法 console.log("child"); } }); var child = new ChildUser; // 建立ChildUser实例 child.sayHello(); // 子类继承父类sayHello()方法 child.sayChild(); // 子类本身的方法 console.log(child.get("name")); // 子类继承父类属性
extend会正确的设置原型链,因此能够经过extend实现继承。上面的代码就是建立父类User,而后子类ChildUser继承子父类。子类会继承父类的属性和方法服务器
var User = Backbone.Model.extend({ defaults : { name : 'tom' // 默认的名字 }, initialize : function(){ //当model建立的时候,调用 console.log("initialize"); this.on('change',function(){ // 当数据发生变化的时候触发 console.log("此时个人名字是:"+this.get("name")); }); } }); var tom = new User; tom.set('name','jack'); // 修改模型的数据,会被change检测到
若是指定了initialize
方法,会在建立实例对象以后调用initialize()
。
当修改了模型数据(经过set()
方法修改数据),会触发自定义事件。app
var User = Backbone.Model.extend({ defaults : { name : 'tom', // 默认的名字 age : 10 }, initialize : function(){ //当model建立的时候,调用 console.log("initialize"); this.on('change:name',function(){ // 只检测name的变化 console.log("此时个人名字是:"+this.get("name")); }); } }); var tom = new User; tom.set('name','jack'); // 修改模型的数据,会被change检测到 tom.set('age','20');// 修改年龄不会被change检测
若是只想检测某个属性的变化,能够经过添加命名空间的方式区别开事件。经过:
的方式给事件添加命名空间。
var BodyView = Backbone.View.extend({ el : $('body'), // 若是没有指定el,el就会是个空div events : { 'click input' : 'sayHello', // 点击input的时候调用sayHello方法 'mouseover li' : 'moveLi'// 鼠标悬浮li标签的时候调用moveLi方法 }, sayHello : function(){ console.log("Hello"); }, moveLi : function(){ console.log("mouseover li"); } }); var view = new BodyView;
若是设置了tagName、className、id、attributes属性(为视图设置根元素),那么view.el
就会被建立,若是没有指定view.el
就是个空的div。
Backbone.events能够写成对象的形式,给视图绑定一组自定义事件。
var Name = Backbone.Model.extend({ defaults : { name : 'tom' } }); var NameView = Backbone.View.extend({ initialize : function(){ this.listenTo( this.model , 'change' , this.showName ); }, showName : function(model){ // $('body').append( "<div>" + model.get("name") + "</div>" ); // 不使用template的时候html代码与js写在一块儿 $('body').append( this.template(this.model.toJSON()) ); // 使用模版以后,html代码与js代码相分离 }, template: _.template($('#name').html()) // _.template中传入须要编译的模版 // 返回的结果就是编译后的html代码 // 最后在showName中调用,将编译后的html显示到body中 }); var name = new Name; var nameView = new NameView({model:name}); name.set('name','jack'); <script type="text/template" id="name"> <% for (var i=0;i<5;i++) { %> <div><%= name %></div> <% } %> </script>
使用js模版不只能够将html代码和js代码分离,提升可读性,也能提升开发效率。backbone.js使用的underscore.js中的template
Backbone.sync = function(method, model) { console.log(method + ": " + JSON.stringify(model)); model.set('id', 1); // 模型的特殊属性 }; var Book = Backbone.Model.extend({ defaults:{ title: "The Rough Riders", author: "Theodore Roosevelt" } }); var b = new Book; b.save(); // create: {"title":"The Rough Riders","author":"Theodore Roosevelt"} b.save({author: "Teddy"}); // update: {"title":"The Rough Riders","author":"Teddy","id":1}
调用模型的save方法,就是委托Backbone.sync对数据进行持久化处理(保存到数据库),若是验证成功返回jqXHR,不然返回false。
sync默认状况下是使用的是jQuery.ajax,能够经过重写sync来使用其余方式进行持久化处理。如WebSockets,XML,或者Local Storage。
上面的代码就是重写Backbone.sync的过程。第一次save
的时候发送的create请求,第二次save的时候发送的是update
请求。
Backbone是如何区分第一次请求仍是第二次请求的呢?
是根据经过model.isNew
这个方法进行判断的。若是模型没有id属性,就是表示模型是新模型。能够经过下面的代码进行测试
Backbone.sync = function(method, model) { console.log(method + ": " + JSON.stringify(model)); console.log(model.isNew()); // 此时不存在id属性,因此是true model.set('id', 1); // 模型的特殊属性 console.log(model.isNew()); // 此时存在id属性,因此是false };
在Model.id文档中指出,若是经过set设置了model的id,就会将这个id拷贝到模型上,做为model的直接属性。在下图中能够发现经过Model.set('id',1)
,给attributes中添加了id属性,也直接给model添加了id属性。
可是相反的,若是用model.id=1
的方式直接给model添加id属性,是不会拷贝到attributes中的。若是只是给model直接添加了id,Model.isNew
返回的一直都会是true。
Backbone.sync = function(method, model) { console.log(method + ": " + JSON.stringify(model)); console.log(model.isNew()); // 返回true model.id=1; // 给model直接添加id属性 console.log(model.isNew()); // 返回true };