(四)backbone - DEMO - 通信录
DEMO介绍
是DEMO - User List 的扩展,增加查询
大体实现
•创建Contact Model
1 var Contact = Backbone.Model.extend({ 2 defaults: { 3 name: '小强', 4 email: 'walker@dead.com' 5 }, 6 // validate user name 7 validate: function(attrs,options) { 8 if (attrs.name == "") { 9 return "what's the name?"; 10 }; 11 }, 12 // for user search 13 filter: function(query) { 14 if (typeof(query) === 'undefined' || query === null || query === '') return true; 15 query = query.toLowerCase(); 16 return this.get('name').toLowerCase().indexOf(query) != -1 || this.get('email').toLowerCase().indexOf(query) != -1; 17 } 18 });
•创建Contact Collection
1 var Contacts = Backbone.Collection.extend({ 2 model: Contact, 3 localStorage: new Store('my-contacts') // 存至本地 4 });
•视图
- 每条联系人视图
1 var ContactItemView = Backbone.View.extend({ 2 className: 'item', 3 template: _.template($('#tpl-item').html()), 4 events: { 5 'click': 'select' 6 }, 7 initialize: function() { 8 _.bindAll(this, 'select'); // select方法绑定到当前对象 9 this.model.bind('reset', this.render, this); 10 this.model.bind('change', this.render, this); 11 this.model.bind('destroy', this.remove, this); 12 if(this.model.view){ 13 this.model.view.remove(); 14 } 15 this.model.view = this; 16 }, 17 render: function() { 18 this.$el.html(this.template(this.model.toJSON())); 19 return this; 20 }, 21 select: function() { // 选择某个联系人 22 appRouter.navigate('contacts/' + this.model.cid, { 23 trigger: true 24 }); 25 }, 26 active: function() { // 选中状态 27 this.$el.addClass('active'); 28 }, 29 deactive: function() { // 未选中状态 30 this.$el.removeClass('active'); 31 } 32 });
- 联系人列表视图,实现功能:
渲染列表、实例化ContactItemView、添加Contact、查询
1 var ContactListView = Backbone.View.extend({ 2 className: 'sidebar', 3 template: _.template($('#tpl-sidebar').html()), 4 events: { 5 'click footer button': 'create', // footer 标签内的 button 标签 click 事件 6 'click input': 'filter', 7 'keyup input': 'filter' 8 }, 9 initialize: function() { 10 _.bindAll(this, 'create', 'filter'); // 给 create,filter 函数绑定到当前对象 11 // model 监听事件 12 this.model.bind('reset', this.renderAll, this); 13 this.model.bind('add', this.add, this); 14 this.model.bind('remove', this.remove, this); 15 }, 16 render: function() { 17 $(this.el).html(this.template()); 18 this.renderAll(); 19 return this; 20 }, 21 renderAll: function() { 22 this.$(".items").empty(); 23 this.model.each(this.renderOne, this); 24 this.filter(); 25 }, 26 renderOne: function(contact) { 27 var view = new ContactItemView({ 28 model: contact 29 }); 30 this.$(".items").append(view.render().el); 31 }, 32 create: function() { 33 var contact = new Contact(); 34 this.model.add(contact); 35 appRouter.navigate('contacts/' + contact.cid + '/edit', { 36 trigger:true 37 }); 38 }, 39 filter: function() { 40 var query = $('input', this.el).val(); 41 this.model.each(function(contact, element, index, list) { 42 contact.view.$el.toggle(contact.filter(query)); 43 }); 44 }, 45 active: function(item){ 46 if (this.activeItem) { 47 this.activeItem.view.deactive(); 48 } 49 this.activeItem = item; 50 if (this.activeItem) { 51 this.activeItem.view.active(); 52 } 53 }, 54 add: function(contact) { 55 this.renderOne(contact); 56 }, 57 remove: function(contact) { 58 console.log(contact); 59 } 60 });
- 显示联系人信息视图,实现:
切换当前联系人,并展示
1 var ShowView = Backbone.View.extend({ 2 className: 'show', 3 template: _.template($('#tpl-show').html()), 4 events: { 5 'click .edit': 'edit' 6 }, 7 initialize: function() { 8 _.bindAll(this, 'edit'); 9 }, 10 render: function() { 11 if(this.item){ 12 this.$el.html(this.template(this.item.toJSON())); 13 } 14 return this; 15 }, 16 change: function(item) { 17 this.item = item; 18 this.render(); 19 }, 20 edit: function() { 21 if (this.item) appRouter.navigate('contacts/' + this.item.cid + '/edit', { 22 trigger: true 23 }); 24 } 25 });
- 编辑联系人信息视图,实现:
修改保存、删除联系人
1 // edit usr contact view 2 var EditView = Backbone.View.extend({ 3 className: 'edit', 4 template: _.template($('#tpl-edit').html()), 5 events: { 6 'submit form': 'submit', 7 'click .save': 'submit', 8 'click .delete': 'remove' 9 }, 10 initialize: function() { 11 _.bindAll(this, 'submit', 'remove'); 12 }, 13 render: function() { 14 if(this.item){ 15 this.$el.html(this.template(this.item.toJSON())); 16 } 17 return this; 18 }, 19 change: function(item) { 20 this.item = item; 21 this.render(); 22 }, 23 submit: function() { 24 this.item.set(this.form()); 25 this.item.save(); 26 appRouter.navigate('contacts/' + this.item.cid, { 27 trigger:true 28 }); 29 return false; 30 }, 31 form: function() { 32 return { 33 name: this.$('form [name="name"]').val(), 34 email: this.$('form [name="email"]').val() 35 }; 36 }, 37 remove: function() { 38 this.item.destroy(); 39 this.item = null; 40 appRouter.navigate('', { 41 trigger: true 42 }); 43 } 44 });
- 主视图,联系人展示、编辑管理视图
实例化展示视图、编辑视图;切换展示视图、编辑视图
1 var MainView = Backbone.View.extend({ 2 className: 'main stack', 3 initialize: function() { 4 this.editView = new EditView(); 5 this.showView = new ShowView(); 6 }, 7 render: function() { 8 this.$el.append(this.showView.render().el); 9 this.$el.append(this.editView.render().el); 10 return this; 11 }, 12 edit: function(item) { 13 this.showView.$el.removeClass('active'); 14 this.editView.$el.addClass('active'); 15 this.editView.change(item); 16 }, 17 show: function(item) { 18 this.editView.$el.removeClass('active'); 19 this.showView.$el.addClass('active'); 20 this.showView.change(item); 21 } 22 });
- 总页面视图:
实例化列表视图、主视图
1 var AppView = Backbone.View.extend({ 2 className: 'contacts', 3 initialize: function() { 4 this.contactList = new ContactListView({ 5 model: this.model 6 }); 7 this.main = new MainView(); 8 this.vdiv = $('<div />').addClass('vdivide'); 9 this.model.fetch(); 10 this.render(); 11 }, 12 render: function() { 13 this.$el.append(this.contactList.render().el); 14 this.$el.append(this.vdiv); 15 this.$el.append(this.main.render().el); 16 $('#article').append(this.el); 17 return this; 18 }, 19 show: function(item){ 20 this.contactList.active(item); 21 this.main.show(item); 22 }, 23 edit: function(item){ 24 this.contactList.active(item); 25 this.main.edit(item); 26 } 27 });
•路由
1 dolymood.contacts = new Contacts(); 2 dolymood.appView = new AppView({ 3 model:dolymood.contacts 4 }); 5 dolymood.AppRouter = Backbone.Router.extend({ 6 routes: { 7 '': 'show', 8 'contacts/:id': 'show', 9 'contacts/:id/edit': 'edit' 10 }, 11 show: function(id) { 12 if(id !== undefined){ 13 dolymood.appView.show(this.getContact(id)); 14 } 15 else { 16 dolymood.appView.show(dolymood.contacts.first()); 17 } 18 }, 19 edit: function(id) { 20 if(id !== undefined){ 21 dolymood.appView.edit(this.getContact(id)); 22 } 23 }, 24 getContact: function(id) { 25 return dolymood.contacts.get(id); 26 } 27 });
注:v1.1.2 版本的Backbone.Collection,使用get函数,传入cid来获取model实例
•路由启动
1 var appRouter = new dolymood.AppRouter(); 2 Backbone.history.start();
•html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>Backbone通讯录</title> 6 <link rel="stylesheet" href="css/application.css" type="text/css" charset="utf-8"> 7 </head> 8 <body> 9 <header id="header"><h1>Backbone通讯录</h1></header> 10 <article id="article"></article> 11 </body> 12 <script src="js/lib/jquery.js" type="text/javascript" charset="utf-8"></script> 13 <script src="js/lib/underscore.js" type="text/javascript" charset="utf-8"></script> 14 <script src="js/lib/backbone.js" type="text/javascript" charset="utf-8"></script> 15 <script src="js/lib/backbone-localstorage.js" type="text/javascript" charset="utf-8"></script> 16 17 <!-- 联系人 --> 18 <script type="text/template" id="tpl-item"> 19 <%= (name ? name : "<i>无名</i>") %> 20 </script> 21 22 <!-- 左边的侧边条,包括联系人列表 --> 23 <script type="text/template" id="tpl-sidebar"> 24 <header> 25 <input type="search" placeholder="搜索" results="0" incremental="true" autofocus> 26 </header> 27 <div class="items"></div> 28 <footer> 29 <button>新建联系人</button> 30 </footer> 31 </script> 32 33 <!-- 显示联系人详细信息 --> 34 <script type="text/template" id="tpl-show"> 35 <header> 36 <a class="edit">编辑</a> 37 </header> 38 <div class="content"> 39 <p><label>姓名:<%= name %></label></p> 40 <p><label>邮箱:<%= email %></label></p> 41 </div> 42 </script> 43 44 <!-- 编辑联系人信息 --> 45 <script type="text/template" id="tpl-edit"> 46 <header> 47 <a class="save">保存</a> 48 <a class="delete">删除</a> 49 </header> 50 <div class="content"> 51 <form> 52 <label> 53 <span>姓名:</span> 54 <input type="text" name="name" value="<%= name %>"> 55 </label> 56 <label> 57 <span>邮箱:</span> 58 <input type="email" name="email" value="<%= email %>"> 59 </label> 60 <button>保存</button> 61 </form> 62 </div> 63 </script> 64 <script src="js/app.js" type="text/javascript" charset="utf-8"></script> 65 </html>