這是一個關於用戶列表以及展示用戶信息的例子,簡單的簡直不像話,但這不是重點,重點是學習了如何基本的使用Backbone。首先來看看效果圖:
1、默認畫面
2、增加(修改)用戶畫面
3、用戶詳情畫面
下面就是這個小東西的實現部分了:
Backbone本身並沒有DOM操作的功能,那咱們肯定離不開DOM操作,這里選擇強大的jquery,當然還可以選擇像zepto, ender等其他庫,另外Backbone還是依賴另外一個也是很出名的庫underscore.由於想要方便,這里就沒有寫后台程序了,用的是瀏覽器本身的localstorage存儲數據,幸運的是Backbone已經給咱們封裝好了backbone.localStorage.js,你只需要引用就可以了。
咱們首先需要存儲每一個用戶數據的model,所以
var User = Backbone.Model.extend({ defaults: { username: '默認用戶名' }, initialize: function() { if (!this.get("username")) { this.set({"username": this.defaults.username}); } if (!this.get("userid")) { this.set({"userid": ++userid}); } } });
defaults,默認的一些數據;在初始化的函數initialize中,咱們只是加入了一些簡單的判斷。
Backbone中有一個Collection集合,是某一類model的集合,咱們這里恰好要用到,因為咱們有一個列表,這是一個整體,咱們用一個Collection來統一管理,更方便,同時也利於做一些事情,例如排序什么的,直接操作集合就ok了。所以咱們這里就創建一個:
var UserCollection = Backbone.Collection.extend({ model: User, // 持久化到本地數據庫 localStorage: new Store("users") });
model:某一類型的Model,默認是Backbone.Model,咱們這里由於是一堆User的集合,所以就設置model為咱們上面創建的User。而localStorage,咱們看到它的值是新創建的一個對象Store,這個Store就是咱們之前引用的backbone.localStorage.js封裝的對象。至於是怎么樣工作的,以后會有對這個文件的分析,咱們目前知道的是這樣寫,咱們就可以達到咱們的數據能夠和localStorage中key是users的某條數據對應就可以了,並且能夠達到同步更新的效果。
好,model這塊基本是可以了,下面就是咱們的重點View,首先想好,需要多少個View,從效果圖中,咱們可以看到,有三個View需要處理,UserListView、UserModifyView、UserView分別對應着列表頁、添加(修改)頁、用戶詳情頁;既然有列表,那么每一個列表項是不是也應該有一個UserItemView呢?在這里咱們加上了,實際上這個需要看時機需求了。好,下面就讓咱們一一實現:
為了方便操作方便,咱們需要一個基礎的View類:
var View = Backbone.View.extend({ register:function (state) { this.state = state; return this; } });
register函數只是方便咱們設置state,state其實是一個model。
(1)列表項UserItemView
var UserItemView = View.extend({ tagName: 'li', template: _.template($('#user-item-template').html()), render: function () { this.$el.html(this.template(this.model.toJSON())); return this; }, events:{ 'click .removeUser': 'deleteUser', 'click .viewUser': 'viewUser' }, viewUser: function() { this.state.trigger('viewUser', this.model); }, deleteUser: function () { this.state.trigger('removeUser', this.model); this.remove(); } });
咱們看到了一些參數,這里需要解釋下:
tagName: 如果不設置默認是'div',也就是盛放咱們view展示內容的外層容器
template: 利用underscore提供的template接口,可以得到一個函數(以后詳細分析)
render: 方便咱們渲染
events: Backbone提供的可以通過鍵值對的形式綁定事件
剩余兩個就是對應的事件處理函數了。
(2)列表UserListView
var UserListView = View.extend({ template: _.template($('#list-template').html()), initialize:function () { var view = this; this.state = new Backbone.Model(); this.router = this.options.router; // 調用fetch的時候觸發reset this.collection.unbind('reset');//注意這里不要重復綁定 this.collection.bind('reset', this.addAll, this);//注意這里不要重復綁定 setTimeout(function() { view.collection.fetch(); }, 0); }, render:function () { var view = this; this.$el.html(this.template(this.state.toJSON())); this.state.on('removeUser', function (user) { user.destroy();//為了修改服務端數據 view.collection.remove(user); }); this.state.on('viewUser', function (user) { view.router.navigate('user/' + user.cid, {trigger:true}); }); return this; }, createUserItemView:function (user) { var userItemView = new UserItemView({ model: user }); userid = Math.max.call(null, user.get('userid'), userid);//確保userid會一直從最大的開始增加 userItemView.register(this.state).render().$el.appendTo($('#list')); }, addAll: function() { this.collection.each(this.createUserItemView.bind(this)); } });
(3)添加(修改)UserModifyView
var UserModifyView = View.extend({ template: _.template($('#modify-template').html()), initialize:function () { this.router = this.options.router; }, render:function () { var view = this; if (this.model) { this.$el.html(this.template(this.model.toJSON())); } else { this.$el.html(this.template({username: ''})); } setTimeout(function() { view.$el.find('input').focus().select();//設置焦點並選中 }, 0); return this; }, events:{ 'click a.add': 'modify' }, modify: function () { var view = this; if (this.model) { this.model.save({'username': this.$el.find('input').val()});//更改服務端數據 } else { this.router.userCollection.create(new User({ username:view.$el.find('input').val(), userid: ++userid })); } this.router.navigate('list', {trigger:true}); } });
(4)最后的詳情頁UserView
var UserView = View.extend({ template: _.template($('#user-template').html()), initialize:function () { this.router = this.options.router; }, render: function () { var view = this; this.$el.html(this.template(this.model.toJSON())); return this; }, events:{ 'click .editUser': 'editUser' }, editUser: function() { this.router.navigate('edit/' + this.model.cid, {trigger:true}); this.remove(); } });
可以看到,在咱們的View中包含了控制器所干的活了,所以說View中包含的是View和Controller兩部分的職責。
咱們到目前為止只是創建了一堆的各種類,咱們需要一個東西來統一管理咱們的小例子,負責一些流程什么的,一般都會選擇叫Application,咱們這里簡單起見就叫App了。
同時,如果想咱們看到不同的畫面的時候意味着地址也跟着改變或者說我點擊瀏覽器的前進后退的時候,也希望能夠很好的工作,怎么辦呢?這就看咱們的Backbone中的Router的作用了,當然他需要Backbone中的history的支持。
先看咱們的App:
var App = Backbone.Router.extend({ initialize:function (el) { this.el = el; //this.userCollection = new UserCollection([new User({username:'張三', userid: ++userid})]); this.userCollection = new UserCollection(); }, routes:{ '':'list', 'list':'list', 'add':'edit', 'edit/:cid':'edit', 'user':'user', 'user/:cid':'user' }, list:function () { var router = this; this.clean(); this.currentView = new UserListView({ collection: router.userCollection, router:router } ).render().$el.appendTo($(this.el)); }, edit:function (cid) { var router = this, user = null; this.clean(); if (cid) { user = router.userCollection.getByCid(cid); } this.currentView = new UserModifyView({ model:user, router:router }).render().$el.appendTo($(this.el)); }, user: function(cid) { var router = this, user = null; this.clean(); if (cid) { user = router.userCollection.getByCid(cid); } this.currentView = new UserView({ model:user, router:router }).render().$el.appendTo($(this.el)); }, clean:function () { if (this.currentView) { this.currentView.remove(); this.currentView = null; } } });
這里解釋下routers: 也是鍵值對,通過這些規則,來完成咱們的整個流程的控制以及歷史的改變。規則是什么呢?這里可以先簡單理解下:
'' | hash值為空 |
'list'(...) | hash: #list |
'edit/:cid' | #edit/111 |
很容易理解,不過這里咱們用到的只是簡單的規則,在后面對Router進行分析的時候會詳細解釋這塊的。
現在還差最后一步了,實例化咱們的App,然后就萬事大吉了
new App('body'); Backbone.history.start();
千萬不能忘記了history的支持,只需要調用start方法即可。
歡迎指導、建議。