從豆瓣說和Backbone.js說開去

來源:互聯網
上載者:User

 

簡而言之,Backbone.js是一個可以在前端組織MVC的javascript架構。

寫的Javascript代碼一旦多起來,沒有一個好的組織,那就會像噩夢一樣。

Backbone提供了Models, Collections, Views。Models 用來建立資料,校正資料,綁定事件,儲存資料到伺服器端;Collections 包含你建立的 functions;Views 用來展示資料。如此這般,在前端也做到了資料和顯示分離。

Backbone依賴於Underscore.js,這是一個有很多常用函數的js檔案(很好用)

下面簡要介紹下Backbone的用法。

 

1. Backbone.Events

Events可以被添加到任何一個javascript對象中,一旦對象與Events合體,就可以自訂事件了。

var obj = {};<br />_.extend(obj, Backbone.Events);<br />obj.bind('data', function(data) {<br />console.log('Receive Data: ' + data);<br />});<br />obj.trigger('data', 'I/'m an Backbone.event');<br />obj.unbind('data');<br />obj.trigger('data', 'I/'m an Backbone.event'); 

如上,一旦使用了_.extend(obj, Backbone.Events),obj對象就獲得了自訂事件的能力。

obj.bind(event, callback) bind方法前面是事件名,後面是回呼函數。bind可以將回呼函數綁定到對象上,事件觸發時便會執行回呼函數。另外,如果事件很多,可以給事件加上命名空間,例如"poll:start", "change:selection"。

obj.unbind([event], [callback]) unbind方法就是移除事件綁定,如果event, callback都沒有,就將移除所有綁定。

obj.trigger(event,[*args]) 觸發事件。

 

2. Backbond.Controller

由於富Ajax的網站大多用帶#的url來識別抓取伺服器內容,因此Backbone也提供了前端的url#fragment的路由支援,並且可以把他們綁定到Action和Event中去。

注意:在使用前端路由的功能之前,一定要調用一次Backbone.history.start()。

我們以豆瓣說的前端代碼為例解說下這個功能。

http://img3.douban.com/anduin/anduin-min-1307608962.js

這堆代碼的最後一個大塊就是Controller的使用。

這一塊的大致結構如下:

App.Controllers.Statuses = Backbone.Controller.extend({<br /> routes: {<br /> "": "home",<br /> "!/comments": "comments",<br /> "!/mentions": "mentions",<br /> "!/:uid": "profile",<br /> "!/:uid/following": "following",<br /> "!/:uid/followers": "followers",<br /> "!/:uid/status/:id": "status",<br /> "!/search/users/:query": "user_search",<br /> "!/search/:query": "search"<br /> },<br /> initialize: function(){...}<br /> home: function(){...}<br /> comments: function() {...}<br /> mentions: function() {...}<br /> profile: function(a) {...}<br /> status: function(a, b) {...}<br /> following: function(a) {...}<br /> followers: function(a) {...}<br /> user_search: function(a) {...}<br /> search: function(a) {...}<br />}); 

這樣我們就很容易看出Backbone.Controller.extend(properties, [classProperties]) 的用法了。properties裡面要有一個routes的雜湊表,提供了路由和方法名的索引值對。

所以我們看到http://shuo.douban.com/#!/comments對應著下面的comments方法。這個頁面對應著“最新回複”模組。

我們還可以看到#fragment裡面有!這個符號,這個是給搜尋引擎識別用的,我們下次在談。

另外,還有:uid, :query, :id這些符號,如果有玩doophp, flask, bottlepy,這些符號應該也很熟悉了,這是動態參數,uid、query、id都是這些參數的參數名,因此

http://shuo.douban.com/#!/search/users/豆瓣

就對應著"!/search/users/:query": "user_search",這個路由,繼而可以用user_search()來處理。

(特別的 "file/*path" 可以匹配#file/nested/folder/file.txt, 參數 "nested/folder/file.txt"會被傳送到相對應的Action中去。)

順便提一句,當url匹配後,會觸發一個和Action名字有關的事件,比如"!/comments": "comments",如果訪問了http://shuo.douban.com/#!/comments,就會觸發"route:comments"的事件,因此我們可以用

controller.bind("route:comments", function(){...});來處理一些額外的邏輯。

 

initialize方法是構造器,初始化,可以加入自訂的相關邏輯。

比如豆瓣說中

initialize: function() {<br /> shuo.themes.loadDefaultTheme();<br /> shuo.loggedIn && (mMy = new User({<br /> uid: UID<br /> }), mMyStat = new Stat, mMyFollowing = new App.Collections.Following([], {<br /> uid: UID,<br /> count: 9<br /> }), cHomeTimeline = new App.Collections.HomeTimeline([],<br /> {<br /> type: STREAM_TYPE_HOME_TIMELINE<br /> }), cSuggestions = new App.Collections.Suggestions([], {<br /> count: 10<br /> }), mMy.fetch(), mMyStat.fetch(), mMyFollowing.fetch())<br /> }, 

每當匹配了一個URL,頁面首先先去除剛才的內容,載入預設的空內容,如果登入了豆瓣說則初始化User(登入使用者),Stat(統計),Following(關注目前使用者的使用者),HomeTimeLine(時間軸),Suggestion,然後用fetch擷取資料。

最後,Controller還有route、saveLocation方法,this.route("page/:number", "page", function(number){ ... });這個方法可以很快的建立一個路由,this.saveLocation("!/comments");可以不觸發hashchange時間的到達另外一個url。

 

3. Backbone.View

View並不操作html或者css,所有的操作留給了各種各樣JS的模板庫。

豆瓣說JS檔案倒數的十幾個塊都是與Backbone.View有關的區塊。

例如:

App.Views.UserInfo = Backbone.View.extend({<br /> model: User,<br /> className: "components cross",<br /> template: $("#user-info-template").html(),<br /> initialize: function() {<br /> _.bindAll(this, "render");<br /> this.model.bind("change", this.render)<br /> },<br /> render: function() {<br /> var a = this.model;<br /> $(this.el).html(Mustache.to_html(this.template, a.toJSON()));<br /> $(this.el).find(".days").html(function() {<br /> var b = a.get("created_at");<br /> return getDays(b)<br /> });<br /> return this<br /> }<br />}); 

在這裡,最外層用了Backbone.View.extend(properties, [classProperties]),在initialize中一旦User類觸發了change事件就會執行render方法,繼而顯示新的視圖。

render方法中總是有個約定俗稱的寫法的。this.el是一個DOM對象,render的目的就是把內容填到this.el中。this.el會根據view提供的tagName, className, id屬性建立,如果一個都沒有,就會建立一個空的DIV。

更新完this.el後,我們還應該return this;這樣才能繼續執行下面的鏈式調用(如果有的話)。

豆瓣說用jquery+mustache來顯示,事實上我們還可以採用haml-js,eco等等模板,js模板在GITHUB上也是多如牛毛的。

 

我們也可以用$(view.el).remove()或者view.remove()很方便的清空DOM。

 

View層有一個委託事件的機制。直接看代碼:

App.Views.Likers = Backbone.View.extend({<br /> className: "likers-manager",<br /> template: $("#likers-components-template").html(),<br /> title_template: "{{#like_count}}<h3>{{like_count}}/u4eba/u8d5e</h3>{{/like_count}}",<br /> events: {<br /> "click .btn-more": "loadMore"<br /> },<br /> initialize: function() {<br /> _.bindAll(this, "render", "updateTitle", "loadOne", "loadAll", "loadMore");<br /> ...<br /> }<br /> render: function() { ... }<br /> updateTitle: function() { ... }<br /> loadOne: function(a) { ... }<br /> loadAll: function() { ... }<br /> loadMore: function(a) { ... }<br />}); 

在這裡面有個events的索引值對,格式為{"event selector": "callback"},其中click為事件,.btn-more是基於this.el為根的選取器,這樣一旦約定好,接下來我們就不需要再去手動呼叫事件方法了。

 

4. Backbone.Model

擴充了Backbone.Model類的對象就會有一些特殊的方法,用來更好地管理對象。通過Backbone.Model.extend(properties, [classProperties]) 擴充成Backbone.Model。第二個參數可選

如下 extend中的方法是可以被子類繼承的。

var Note = Backbone.Model.extend({<br /> initialize: function() { ... },<br /> author: function() { ... },<br /> coordinates: function() { ... },<br /> allowedToEdit: function(account) {<br /> return true;<br /> }<br />});<br />var PrivateNote = Note.extend({<br /> allowedToEdit: function(account) {<br /> return account.owns(this);<br /> }<br />}); 

豆瓣說中的Backbone.Model都寫得比較簡單

var User = Backbone.Model.extend({<br /> initialize: function() {<br /> this.url = "/api/users/" + this.get("uid");<br /> shuo.loggedIn && this.get("uid") === UID && this.set({<br /> i: !0<br /> })<br /> }<br />}); 

get/set用法是Model的一個特色

此外Model還有不少欄位和方法,像id, cid, excape,unset,clear,attributes, defaults等等。

內容比較繁雜,下次研究。

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.