前言
昨天我们一起学习了Backbone,最后做了一个备忘录的例子,说是做了不如说是看了下官方提供的例子,所以最终我感觉我们还是没能掌握Backbone,今天还得做个其它例子先。
然后前面也只是草草学习了RequireJS,没做demo,这个周末又在看电影打游戏睡觉瞎折腾,转眼就周日下午了,突然诗性大起,于是作诗一首先:
古有通宵看A片,今有彻夜码代码
好吧,我们开始今天的学习吧,我们今天先用backbone做一个通讯录的东西,然后使用requireJS组装之。
部分参考:the5fire的技术博客
简单例子
做之前我们先来个简单的例子:
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 </head> 5 <body> 6 <div id="contactapp"> 7 <header> 8 <h1> 9 通讯录</h1> 10 </header> 11 <section id="main"> 12 <ul id="contact-list"> 13 </ul> 14 </section> 15 <div class="create"> 16 <input type="button" value="增加(弹出框)" id="addDia" /> 17 </div> 18 </div> 19 </body> 20 <script src="js/jquery.js" type="text/javascript"></script> 21 <script src="js/underscore.js" type="text/javascript"></script> 22 <script src="js/backbone.js" type="text/javascript"></script> 23 <script type="text/javascript"> 24 (function ($) { 25 var Contact = Backbone.Model.extend({ 26 //创建一个contact对象,拥有name属性 27 name: null 28 }); 29 var ContackList = Backbone.Collection.extend({ 30 initialize: function (models, options) { 31 //contact集合 32 this.bind('add', options.view.addOne); 33 } 34 }); 35 var AppView = Backbone.View.extend({ 36 el: $('body'), 37 initialize: function () { 38 //实例化集合,并传入AppView对象 39 this.contacts = new ContackList(null, { view: this }); 40 }, 41 events: { 42 'click #addDia': 'addDia' 43 }, 44 addDia: function () { 45 var name = prompt('请输入姓名'); 46 var c = new Contact({ name: name }); 47 this.contacts.add(c); 48 }, 49 addOne: function (model) { 50 $('#contact-list').append('<li>' + model.get('name') + '</li>'); 51 } 52 }); 53 var app = new AppView(); 54 })(jQuery); 55 </script> 56 </html>
PS:感谢the5fire给出的例子,我和我的小伙伴一下都明白了。。。。
以上代码涉及到Backbone三个部分:View、Model、Collection,我们在addOne里面使用了jquery绑定dom以后会将之消除。
各位请看这个代码:
this.bind('add', options.view.addOne);
在集合中绑定了add事件,在addDia最后执行了,然后触发集合的事件,才最后将dom添加完成。
知识回顾(参考the5fire)
the5fire关于backbone的文章写的很好(http://www.the5fire.com),我们一起来看看顺便回顾下我们的知识。
model
Man = Backbone.Model.extend({ initialize: function(){ alert('Hey, you create me!'); } }); var man = new Man;
这个是一个model最简单的model,initialize中的方法一来就会执行,这里就会弹出框:
对象赋值
Man = Backbone.Model.extend({ initialize: function () { alert('Hey, you create me!'); }, defaults: { name: '张三', age: '38' } }); var man = new Man; alert(man.get('name')); //man.set({ name: 'the5fire', age: '10' });
若是不赋值就使用默认值,若是赋值则采用给的值。
事件与方法
Man = Backbone.Model.extend({ initialize: function(){ alert('Hey, you create me!'); //初始化时绑定监听 this.bind("change:name",function(){ var name = this.get("name"); alert("你改变了name属性为:" + name); }); }, defaults: { name:'张三', age: '38' }, aboutMe: function(){ return '我叫' + this.get('name') + ',今年' + this.get('age') + '岁'; } }); var man = new Man; man.set({name:'the5fire'}) //触发绑定的change事件,alert。
可以定义方法aboutMe,也可以在initialize中绑定事件以监听某个属性的变化。
验证及错误提示
Man = Backbone.Model.extend({ initialize: function () { this.bind("error", function (model, error) { alert(error); }); }, validate: function (attributes) { if (attributes.name == '') { return "name不能为空!"; } }, }); var man = new Man; man.set({ name: '' }); //根据验证规则,弹出错误提示。
此处验证不通过便会触发错误提示。
PS:经测试并没有提示,问题后面跟进
PS:最后证明有反应,我调试页面用错了
对象持久化
对象持久化可以是服务器也可以是本地存储,具体就不展开了。
collection
集合其实就是model的有序集合,经过周末的学习,我们应该比较熟悉了:
Book = Backbone.Model.extend({ defaults: { // 感谢网友蓝色动力指正改为defaults title: 'default' }, initialize: function () { //alert('Hey, you create me!'); } }); BookShelf = Backbone.Collection.extend({ model: Book }); var book1 = new Book({ title: 'book1' }); var book2 = new Book({ title: 'book2' }); var book3 = new Book({ title: 'book3' }); //var bookShelf = new BookShelf([book1, book2, book3]); //注意这里面是数组,或者使用add var bookShelf = new BookShelf; bookShelf.add(book1); bookShelf.add(book2); bookShelf.add(book3); bookShelf.remove(book3); //基于underscore这个js库,还可以使用each的方法获取collection中的数据 bookShelf.each(function (book) { alert(book.get('title')); });
fetch
我们若是要与服务器通讯获取数据,需要先为bookshelf定义url:
bookShelf.fetch({ url: '/getbooks/', success: function (collection, response) { collection.each(function (book) { alert(book.get('title')); }); }, error: function () { alert('error'); } });
//对应的BookShelf的返回格式如下: [{'title':'book1'},{'title':'book2'}.....]
此后我们需要将页面的dom与数据同步,所以会用到reset事件;
bookShelf.bind('reset',showAllBooks); showAllBooks = function(){ bookShelf.each(function(book){ //将book数据渲染到页面。 }); }
1 <html> 2 <head> 3 <title>the5fire-backbone-collection</title> 4 </head> 5 <body> 6 </body> 7 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script> 8 <script src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.4/underscore-min.js"></script> 9 <script src="http://ajax.cdnjs.com/ajax/libs/backbone.js/0.3.3/backbone-min.js"></script> 10 <script> 11 (function ($) { 12 //collection是一个简单的models的有序集合 13 //1、一个简单的例子 14 15 Book = Backbone.Model.extend({ 16 defaults : { // 感谢网友蓝色动力指正改为defaults 17 title:'default' 18 }, 19 initialize: function(){ 20 //alert('Hey, you create me!'); 21 } 22 }); 23 BookShelf = Backbone.Collection.extend({ 24 model : Book 25 }); 26 27 var book1 = new Book({title : 'book1'}); 28 var book2 = new Book({title : 'book2'}); 29 var book3 = new Book({title : 'book3'}); 30 31 //var bookShelf = new BookShelf([book1, book2, book3]); //注意这里面是数组,或者使用add 32 var bookShelf = new BookShelf; 33 bookShelf.add(book1); 34 bookShelf.add(book2); 35 bookShelf.add(book3); 36 bookShelf.remove(book3); 37 /* 38 for(var i=0; i<bookShelf.models.length; i++) { 39 alert(bookShelf.models[i].get('title')); 40 } 41 */ 42 //基于underscore这个js库,还可以使用each的方法获取collection中的数据 43 bookShelf.each(function(book){ 44 alert(book.get('title')); 45 }); 46 47 //2、使用fetch从服务器端获取数据,使用reset渲染 48 bookShelf.bind('reset', showAllBooks); 49 bookShelf.fetch({url:'/getbooks/',success:function(collection,response){ 50 collection.each(function(book){ 51 alert(book.get('title')); 52 }); 53 },error:function(){ 54 alert('error'); 55 }}); 56 showAllBooks = function(){ 57 bookShelf.each(function(book){ 58 //将book数据渲染到页面。 59 }); 60 } 61 //上述代码仅仅均为可正常执行的代码,不过关于服务器端的实例在后面会有。 62 })(jQuery); 63 </script> 64 </html>
Router(之前好像没看到)
之前我们学习的时候好像错过了Router了,路由的出现是想控制URL呢,Backbone.Router会把#标签当做url路径。
1 <html> 2 <head> 3 <title>the5fire-backbone-router</title> 4 </head> 5 <body> 6 <a href="#/posts/120">Post 120</a> 7 <a href="#/download/user/images/hey.gif">download gif</a> 8 <a href="#/dashboard/graph">Load Route/Action View</a> 9 </body> 10 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script> 11 <script src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.4/underscore-min.js"></script> 12 <script src="http://documentcloud.github.com/backbone/backbone-min.js"></script> 13 <script> 14 (function ($) { 15 //Backbone中的router,见名知意,router有路由的意思,显然这里是要控制url的。 16 //Backbone.Router会把你连接中的#标签当做是url路径 17 /** 18 //1、来看一个简单的例子 19 var AppRouter = Backbone.Router.extend({ 20 routes: { 21 "*actions" : "defaultRoute" 22 }, 23 defaultRoute : function(actions){ 24 alert(actions); 25 } 26 }); 27 28 var app_router = new AppRouter; 29 30 Backbone.history.start(); 31 32 33 //2、既然是对url进行匹配那么它应该不仅仅只是简单的静态匹配,应该具有传递参数的功能,所以下面再来一个动态的router的例子. 34 var AppRouter = Backbone.Router.extend({ 35 routes: { 36 "/posts/:id" : "getPost", 37 "*actions" : "defaultRoute" 38 }, 39 getPost: function(id) { 40 alert(id); 41 }, 42 defaultRoute : function(actions){ 43 alert(actions); 44 } 45 }); 46 47 var app_router = new AppRouter; 48 49 Backbone.history.start(); 50 **/ 51 //从上面已经可以看到匹配#标签之后内容的方法,有两种:一种是用“:”来把#后面的对应的位置作为参数;还有一种是“*”,它可以匹配所有的url,下面再来演练一下。 52 var AppRouter = Backbone.Router.extend({ 53 routes: { 54 "/posts/:id" : "getPost", 55 "/download/*path": "downloadFile", //对应的链接为<a href="#/download/user/images/hey.gif">download gif</a> 56 "/:route/:action": "loadView", //对应的链接为<a href="#/dashboard/graph">Load Route/Action View</a> 57 "*actions" : "defaultRoute" 58 }, 59 getPost: function(id) { 60 alert(id); 61 }, 62 defaultRoute : function(actions){ 63 alert(actions); 64 }, 65 downloadFile: function( path ){ 66 alert(path); // user/images/hey.gif 67 }, 68 loadView: function( route, action ){ 69 alert(route + "_" + action); // dashboard_graph 70 } 71 }); 72 73 var app_router = new AppRouter; 74 75 Backbone.history.start(); 76 77 })(jQuery); 78 </script> 79 80 </html>
我们暂时不管这个,否则任务完成不了了。
View
这个看完,我们就要继续今天的学习了,这里用了太多时间啦。
backbone的view是用来显示model数据到页面的,同时监听dom事件并相应变化。
来看看我们的页面主体:
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 </head> 5 <body> 6 <div id="search_container"> 7 </div> 8 <script type="text/template" id="search_template"> 9 <label><%= search_label %></label> 10 <input type="text" id="search_input" /> 11 <input type="button" id="search_button" value="Search" /> 12 </script> 13 </body> 14 <script src="js/jquery.js" type="text/javascript"></script> 15 <script src="js/underscore.js" type="text/javascript"></script> 16 <script src="js/backbone.js" type="text/javascript"></script> 17 <script type="text/javascript"> 18 (function ($) { 19 //此处添加下面的试验代码 20 })(jQuery); 21 </script> 22 </html>
el属性
该属性引用dom中的一些元素,每个view都会有这个属性,没有声明就默认创建空div
(function ($) { SearchView = Backbone.View.extend({ initialize: function () { //this.render(); }, render: function () { //使用underscore这个库,来编译模板 var template = _.template($("#search_template").html(), {}); //加载模板到对应的el属性中 //this.el.html(template); //感谢 子不语同学指正。 $(this.el).html(template); } }); var searchView = new SearchView({ el: $("#search_container") }); searchView.render(); //这个reander的方法可以放到view的构造函数中 })(jQuery);
[这里有一个错误,因为这个例子里没有传入search_label这个变量,所以你运行的时候要把html的模板中的那个变量改掉才行。]
事件绑定
(function ($) { SearchView = Backbone.View.extend({ initialize: function () { this.render(); }, render: function () { //使用underscore这个库,来编译模板 var template = _.template($("#search_template").html(), {}); //加载模板到对应的el属性中 //this.el.html(template); $(this.el).html(template); }, events: { //就是在这里绑定的 'click input[type=button]': 'doSearch' //定义类型为button的input标签的点击事件,触发函数doSearch }, doSearch: function (event) { alert("search for " + $("#search_input").val()); } }); var searchView = new SearchView({ el: $("#search_container") }); })(jQuery);
模板
此处的模板,就是以数据替换其中的特殊标签<%= search_label %>
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 </head> 5 <body> 6 <div id="search_container"> 7 </div> 8 <script type="text/template" id="search_template"> 9 <label><%= search_label %></label> 10 <input type="text" id="search_input" /> 11 <input type="button" id="search_button" value="Search" /> 12 </script> 13 </body> 14 <script src="js/jquery.js" type="text/javascript"></script> 15 <script src="js/underscore.js" type="text/javascript"></script> 16 <script src="js/backbone.js" type="text/javascript"></script> 17 <script type="text/javascript"> 18 (function ($) { 19 SearchView = Backbone.View.extend({ 20 initialize: function () { 21 this.render('the5fire'); 22 }, 23 render: function (search_label) { 24 //使用underscore这个库,来编译模板 25 var template = _.template($("#search_template").html(), { search_label: search_label }); 26 //加载模板到对应的el属性中 27 $(this.el).html(template); 28 }, 29 events: { //就是在这里绑定的 30 'click input[type=button]': 'doChange' 31 }, 32 doChange: function (event) { 33 //通过model发送数据到服务器 34 this.render('the5fire' + $("#search_input").val()); 35 } 36 }); 37 var searchView = new SearchView({ el: $("#search_container") }); 38 })(jQuery); 39 </script> 40 </html>
阶段总结
好了,知识回顾暂时到这里,我们要来我们的东西了,不然搞不完了。
HTML结构
有点一头雾水的感觉,于是先上一张图吧:
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 </head> 5 <body> 6 <div id="contactapp"> 7 <header> 8 <h1> 9 通讯录</h1> 10 </header> 11 <section id="main"> 12 <ul id="contact-list"> 13 </ul> 14 </section> 15 <div class="create"> 16 <label> 17 姓名:<input type="text" id="name" /></label> 18 <label> 19 电话:<input type="text" id="phone" /></label> 20 <input type="button" value="保存" id="add" /> 21 </div> 22 </div> 23 </body> 24 </html>
下面的输入框用以新建通讯项目,contact-list用以显示通讯录列表。整个页面非常简单,我们先就完成这个功能即可。
模型与集合
完了我们应该创建Contact模型了,我们先来随便写写代码看看有神马情况发生:
var Contact = Backbone.Model.extend({ validate: function (attr) { if (!attr.name || attr.name.length > 5) { return '姓名格式错误'; } } }); var contact = new Contact(); var s = '';
这里根据backbone的Model的extend方法建立了Contact模型。
其中可能会有验证机制,我这里随便写了一个,电话其实也需要验证的。
而模型会有的方法,我们暂时不管他了,先来个集合吧:
<script src="js/underscore.js" type="text/javascript"></script> <script src="js/backbone.js" type="text/javascript"></script> <script src="js/backbone.localStorage.js" type="text/javascript"></script> <script type="text/javascript"> var Contact = Backbone.Model.extend({ validate: function (attr) { if (!attr.name || attr.name.length > 5) { return '姓名格式错误'; } } }); var ContackList = Backbone.Collection.extend({ model: ContackList, localStorage: new Store('contacts')//所有信息保存至contacts空间下,注意此次用到了本地存储的东西 }); var s = ''; </script>
这里使用了本地存储,所以我们必须设置localStorage属性。
视图
现在我们来设置视图后:
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 </head> 5 <body> 6 <div id="contactapp"> 7 <header> 8 <h1> 9 通讯录</h1> 10 </header> 11 <section id="main"> 12 <ul id="contact-list"> 13 </ul> 14 </section> 15 <div class="create"> 16 <label> 17 姓名:<input type="text" id="name" /></label> 18 <label> 19 电话:<input type="text" id="phone" /></label> 20 <input type="button" value="保存" id="add" /> 21 </div> 22 </div> 23 </body> 24 <script src="js/jquery.js" type="text/javascript"></script> 25 <script src="js/underscore.js" type="text/javascript"></script> 26 <script src="js/backbone.js" type="text/javascript"></script> 27 <script src="js/backbone.localStorage.js" type="text/javascript"></script> 28 <script type="text/javascript"> 29 (function ($) { 30 var Contact = Backbone.Model.extend({ 31 validate: function (attr) { 32 if (!attr.name || attr.name.length > 5) { 33 return '姓名格式错误'; 34 } 35 } 36 }); 37 38 var ContackList = Backbone.Collection.extend({ 39 model: ContackList, 40 localStorage: new Store('contacts'), //所有信息保存至contacts空间下,注意此次用到了本地存储的东西 41 initialize: function (models, options) { 42 this.bind('add', options.view.add); 43 } 44 }); 45 var AppView = Backbone.View.extend({ 46 el: $('body'), 47 tmplate: _.template('<li><%= name %>:<%= phone %></li>'), 48 49 initialize: function () { 50 _.bindAll(this, 'save', 'add'); 51 this.contacts = new ContackList(null, { view: this }); 52 this.list = $('#contact-list'); 53 this.name = $('#name'); 54 this.phone = $('#phone'); 55 }, 56 events: { 57 'click #add': 'save' 58 }, 59 save: function () { 60 var model = new Contact({ name: this.name.val(), phone: this.phone.val() }); 61 this.contacts.add(model); 62 }, 63 add: function (model) { 64 var obj = model.toJSON(); 65 $(this.list).append(this.tmplate(obj)); 66 } 67 }); 68 var app = new AppView(); 69 70 })(jQuery); 71 </script> 72 </html>
我们的简单的界面终于出来了。。。。于是我们来优化加功能吧:
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 </head> 6 <body> 7 <div id="contactapp"> 8 <header> 9 <h1> 10 通讯录</h1> 11 </header> 12 <section id="main"> 13 <ul id="contact-list"> 14 </ul> 15 </section> 16 <div class="create"> 17 <label> 18 姓名:<input type="text" id="name" /></label> 19 <label> 20 电话:<input type="text" id="phone" /></label> 21 <input type="button" value="保存" id="add" /> 22 </div> 23 </div> 24 </body> 25 <script src="js/jquery.js" type="text/javascript"></script> 26 <script src="js/underscore.js" type="text/javascript"></script> 27 <script src="js/backbone.js" type="text/javascript"></script> 28 <script src="js/backbone.localStorage.js" type="text/javascript"></script> 29 <script type="text/javascript"> 30 (function ($) { 31 var Contact = Backbone.Model.extend({ 32 initialize: function () { 33 this.bind("error", function (model, error) { 34 alert(error); 35 }); 36 }, 37 validate: function (attr) { 38 if (attr.name.length == '') { 39 return '姓名格式错误'; 40 } 41 } 42 }); 43 var ContactList = Backbone.Collection.extend({ 44 model: Contact, 45 localStorage: new Store('contacts') //所有信息保存至contacts空间下,注意此次用到了本地存储的东西 46 47 }); 48 var list = new ContactList(); 49 var ContactView = Backbone.View.extend({ 50 tagName: 'li', 51 template: _.template('<div><%= name %>:<%= phone %></div>'), 52 events: { 53 'click li': 'test' 54 }, 55 initialize: function () { 56 _.bindAll(this, 'render', 'remove'); 57 this.model.bind('change', this.render); 58 this.model.bind('destroy', this.remove); 59 }, 60 render: function () { 61 var html = this.template(this.model.toJSON()); 62 //this.el是生成的空div 63 $(this.el).html(html); 64 //返回了当前视图 65 return this; 66 }, 67 remove: function () { 68 $(this.el).remove(); 69 }, 70 test: function () { 71 alert(this); 72 var s = ''; 73 } 74 }); 75 var AppView = Backbone.View.extend({ 76 el: $('body'), 77 events: { 78 'click #add': 'save' 79 }, 80 initialize: function () { 81 this.name = this.$('#name'); 82 this.phone = this.$('#phone'); 83 this.list = this.$('#contact-list'); 84 85 _.bindAll(this, 'render', 'add', 'loadList', 'save'); 86 //为集合绑定事件 87 list.bind('add', this.add); 88 //添加修改时触发 89 list.bind('refresh', this.loadList); 90 list.fetch(); 91 }, 92 //添加项目 93 add: function (model) { 94 var view = new ContactView({ model: model }); 95 this.list.append(view.render().el); 96 // view.model.save({ name: model.name, phone: model.phone }); 97 var s = ''; 98 }, 99 loadList: function () { 100 list.each(this.add); 101 }, 102 save: function () { 103 var name = this.name.val(); 104 var phone = this.phone.val(); 105 list.create({ name: name, phone: phone }); 106 this.name.val(''); 107 this.phone.val(''); 108 } 109 }); 110 var app = new AppView(); 111 112 })(jQuery); 113 </script> 114 </html>
这个代码与上述代码有些不同,我们来理一理:
① 模型与集合变化不大
② 具有2个视图:
通讯录视图,我们后面通讯录会有编辑、删除或者其他功能,就在此上写
全局视图,AppView用于全局,可能还会显示整体状态。
③流程
因为我们只有一个通讯录列表,所以将之全局化出来了:
var list = new ContactList();
ContactView主要关注自身,与整体可以隔离开。
tagName指定了形成的dom的外层结构,不指定就是div
template会解析模板,我直接写到这里了,后面我们做点修改给个删除功能
template: _.template('<div><%= name %>:<%= phone %><a href="javascript:;">[删除]</a></div>'),
events就是绑定的事件
PS:具体代码各位自己看吧......
这里将删除事件加上就算阶段完成了:
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 </head> 6 <body> 7 <div id="contactapp"> 8 <header> 9 <h1> 10 通讯录</h1> 11 </header> 12 <section id="main"> 13 <ul id="contact-list"> 14 </ul> 15 </section> 16 <div class="create"> 17 <label> 18 姓名:<input type="text" id="name" /></label> 19 <label> 20 电话:<input type="text" id="phone" /></label> 21 <input type="button" value="保存" id="add" /> 22 </div> 23 </div> 24 </body> 25 <script src="js/jquery.js" type="text/javascript"></script> 26 <script src="js/underscore.js" type="text/javascript"></script> 27 <script src="js/backbone.js" type="text/javascript"></script> 28 <script src="js/backbone.localStorage.js" type="text/javascript"></script> 29 <script type="text/javascript"> 30 (function ($) { 31 var Contact = Backbone.Model.extend({ 32 initialize: function () { 33 this.bind("error", function (model, error) { 34 alert(error); 35 }); 36 }, 37 validate: function (attr) { 38 if (attr.name.length == '') { 39 return '姓名格式错误'; 40 } 41 } 42 }); 43 var ContactList = Backbone.Collection.extend({ 44 model: Contact, 45 localStorage: new Store('contacts') //所有信息保存至contacts空间下,注意此次用到了本地存储的东西 46 47 }); 48 var list = new ContactList(); 49 var ContactView = Backbone.View.extend({ 50 tagName: 'li', 51 template: _.template('<div><%= name %>:<%= phone %><a href="javascript:;" class="delete">[删除]</a></div>'), 52 events: { 53 'click .delete': 'destroy' 54 }, 55 initialize: function () { 56 _.bindAll(this, 'render', 'remove'); 57 this.model.bind('change', this.render); 58 this.model.bind('destroy', this.remove); 59 }, 60 render: function () { 61 var html = this.template(this.model.toJSON()); 62 //this.el是生成的空div 63 $(this.el).html(html); 64 //返回了当前视图 65 return this; 66 }, 67 destroy: function () { 68 this.model.destroy(); 69 }, 70 remove: function () { 71 $(this.el).remove(); 72 73 } 74 }); 75 var AppView = Backbone.View.extend({ 76 el: $('body'), 77 events: { 78 'click #add': 'save' 79 }, 80 initialize: function () { 81 this.name = this.$('#name'); 82 this.phone = this.$('#phone'); 83 this.list = this.$('#contact-list'); 84 85 _.bindAll(this, 'render', 'add', 'loadList', 'save'); 86 //为集合绑定事件 87 list.bind('add', this.add); 88 //添加修改时触发 89 list.bind('refresh', this.loadList); 90 list.fetch(); 91 }, 92 //添加项目 93 add: function (model) { 94 var view = new ContactView({ model: model }); 95 this.list.append(view.render().el); 96 // view.model.save({ name: model.name, phone: model.phone }); 97 var s = ''; 98 }, 99 loadList: function () { 100 list.each(this.add); 101 }, 102 save: function () { 103 var name = this.name.val(); 104 var phone = this.phone.val(); 105 list.create({ name: name, phone: phone }); 106 this.name.val(''); 107 this.phone.val(''); 108 } 109 }); 110 var app = new AppView(); 111 112 })(jQuery); 113 </script> 114 </html>
阶段总结
我们又简单的回顾了下backbone,这次学习后我和我的小伙伴表示都懂了。。。。
整合requireJS
先上个图:
尼玛,一下多出了好多文件:
模型
define(function () { var Contact = Backbone.Model.extend({ initialize: function () { this.bind("error", function (model, error) { alert(error); }); }, validate: function (attr) { if (attr.name.length == '') { return '姓名格式错误'; } } }); return Contact; });
集合
define(['model/contact'], function (Contact) { var ContactList = Backbone.Collection.extend({ model: Contact, localStorage: new Store('contacts') //所有信息保存至contacts空间下,注意此次用到了本地存储的东西 }); return ContactList; });
contact视图
define(function () { var ContactView = Backbone.View.extend({ tagName: 'li', template: _.template('<div><%= name %>:<%= phone %><a href="javascript:;" class="delete">[删除]</a></div>'), events: { 'click .delete': 'destroy' }, initialize: function () { _.bindAll(this, 'render', 'remove'); this.model.bind('change', this.render); this.model.bind('destroy', this.remove); }, render: function () { var html = this.template(this.model.toJSON()); //this.el是生成的空div $(this.el).html(html); //返回了当前视图 return this; }, destroy: function () { this.model.destroy(); }, remove: function () { $(this.el).remove(); } }); return ContactView; });
全局视图
define(['collection/contact', 'view/contact'], function (contact, ContactView) { window.list = new contact(); var AppView = Backbone.View.extend({ el: $('body'), events: { 'click #add': 'save' }, initialize: function () { this.name = this.$('#name'); this.phone = this.$('#phone'); this.list = this.$('#contact-list'); _.bindAll(this, 'render', 'add', 'loadList', 'save'); //为集合绑定事件 list.bind('add', this.add); //添加修改时触发 list.bind('refresh', this.loadList); list.fetch(); }, //添加项目 add: function (model) { var view = new ContactView({ model: model }); this.list.append(view.render().el); // view.model.save({ name: model.name, phone: model.phone }); var s = ''; }, loadList: function () { list.each(this.add); }, save: function () { var name = this.name.val(); var phone = this.phone.val(); list.create({ name: name, phone: phone }); this.name.val(''); this.phone.val(''); } }); return AppView; });
main函数
require.config({ paths: { jquery: 'js/jquery', underscore: 'js/underscore', backbone: 'js/backbone', bl: 'js/backbone.localStorage' } }); require(['jquery', 'underscore', 'backbone', 'bl', 'model/contact', 'collection/contact', 'view/contact', 'view/app'], function ($, _, b, bl, model, collection, view, app) { var app = new app(); });
HTML页面
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <body> <div id="contactapp"> <header> <h1> 通讯录</h1> </header> <section id="main"> <ul id="contact-list"> </ul> </section> <div class="create"> <label> 姓名:<input type="text" id="name" /></label> <label> 电话:<input type="text" id="phone" /></label> <input type="button" value="保存" id="add" /> </div> </div> </body> <script src="js/require.js" data-main="main" type="text/javascript"></script> </html>
于是,我们功能完成了:
结语
我和我的小伙伴说,尼玛终于搞完了。。。。。。