前言
之前嘗試性的讀了下backbone的源碼,對繼承、事件、view一塊還比較熟悉,看下去比較順暢,但是在model collection方面就很不順利
究其原因還是沒有使用過,不夠熟悉,以碼讀碼,脫離了業務邏輯的代碼毫無意義,是以今天我們先來做一個例子吧,然後再根據例子學習
今天來一段官網以外的代碼,本來這裡想抄一個代碼來着,但是這樣的話好像意義就不大了,于是自己重新寫一個例子吧
注意這個例子隻是簡單例子,各位不要當真,而且代碼是今天下午寫的,有BUG不要罵我,然後放到IIS環境下才有資料
下載下傳源碼:02backbone.zip
單頁應用執行個體
以部落格園為例,我們一起做一個單頁,提供list和detail兩個頁面,并且為list提供分頁和簡單篩選功能來鞏固我們的backbone學習
檔案結構
首先為了簡單起見,我們這裡目錄暫時如下:
其中css樣式是上次做單頁應用研究剩下的,這次直接拿來用吧
資料源
然後,我們來簡單看看我們部落格園的資料源傳回的資料:
很遺憾部落格園暫時隻提供了xml的傳回格式,其中我自己做了json的解析,其實就算我自己不做解析,也可以通過model的parse做解析
但是我沒有那麼蛋疼,這裡還是使用背景方法解析吧
Model/Collection
有了資料源,我們就需要對其建立資料模型了,這裡可以與他統一反正資料model會自己對應
我們知道Model可以設定URL,自己從伺服器擷取資料(隻不過必須是rest請求),我們這裡來試試
1 //部落格模型
2 var PostModel = Backbone.Model.extend({
3
4 });
5
6 //模型集合
7 var PostList = Backbone.Collection.extend({
8 model: PostModel
9 });
10 var curpage = 1;
11 var pageSize = 10;
12 var list = new PostList();
13 list.url = 'Handler.ashx?url=http://wcf.open.cnblogs.com/blog/sitehome/paged/' + curpage + '/' + pageSize;
14 list.fetch();
我們這裡事實上隻需要擷取資料即可,如此變會發起一個請求,資料傳回與上述截圖一緻
有了資料我們就需要根據資料對model進行填充,一次執行個體化model加入collection
我們這裡使用parse對傳回資料進行處理,于是他自己就将model填充到model裡面去了
parse: function (data) {
// 'data' contains the raw JSON object
return (data && data.feed && data.feed.entry) || {}
}
list.fetch({
success: function () {
var s = '';
}
});
需要注意一點是這裡是異步的,是以不要傻傻的馬上想在後面操作資料
視圖-View
現在資料模型與集合都有了,我們需要一個承載他的頁面,于是我們先随便搞下将資料顯示出來:
① 定義模闆
1 <script type="text/template" id="item-template">
2 <li class="arr_r orderItem" data-id="<%=id %>">
3 <article class="blog_item">
4 <h3>
5 <a href="<%=link.href %>" target="_blank">
6 <%=title.value || '無題' %></a>
7 </h3>
8 <div class="author pro_list_rank">
9 <%if(author.avatar){ %>
10 <a href="<%=author.uri %>" target="_blank">
11 <img src="<%=author.avatar %>">
12 </a>
13 <%} %>
14 <%=summary.value %>
15 </div>
16 <div class="item_footer">
17 <a href="<%=author.uri %>" class="lightblue">Scut</a>
18 <%=published %>
19 <a href="<%=link.href %>" title="2013-08-21 15:21" class="gray">評論(<%=comments %>)</a>
20 <a href="<%=link.href %>" class="gray">閱讀(<%=views %>)</a> <span class="price1">推薦(<%=diggs %>)</span></div>
21 </article>
22 </li>
23 </script>
這是我們之前使用過的資料模闆,這裡直接搞過來使用了
② 定義view
并在集合資料加載結束調用render方法
1 var View = Backbone.View.extend({
2 template: _.template($('#item-template').html()),
3 initialize: function () {
4 var scope = this;
5 var curpage = 1;
6 var pageSize = 10;
7 this.list = new PostList();
8 this.list.url = 'Handler.ashx?url=http://wcf.open.cnblogs.com/blog/sitehome/paged/' + curpage + '/' + pageSize;
9 this.list.fetch({
10 success: function () {
11 scope.render();
12 }
13 });
14 this.wrapper = $('#lstbox');
15 },
16 render: function () {
17 var models = this.list.models;
18 var html = '';
19 for (var i = 0, len = models.length; i < len; i++) {
20 html += this.template(models[i].toJSON());
21
22 }
23 this.wrapper.html(html);
24 var s = '';
25 }
26 });
③ 執行個體化view
var view = new View();
于是我們的view就出來了:
附上完整html代碼:
完整Html代碼
到現在為止,我們隻是簡單将視圖展示了出來,現在我們來多用一點集合與模型的操作,深入之前的學習
操作集合/模型
這裡又有個比較遺憾的地方就是,我們并不需要寫資料到伺服器,我這裡也不準備調用寫的接口,是以model又被邊緣化了......
集合排序
我們這裡對下面的幾個做一個排序處理,比如按時間排序,按推薦數排序等,這裡就要用的集合裡面的操作了
然後我們來看看我們如何隻改變集合的資料,而讓dom自己發生變化
有一點需要注意的是,我們現在還不是完整的單頁,後面引入路由時候慢慢改程序式結構
首先我們需要為下面幾個可愛的按鈕綁定點選事件:
1 <ul class="tab_search fix_bottom" id="sort">
2 <li class="tabcrt" attr="time">時間</li>
3 <li class="tab_hotel" attr="recommend">推薦</li>
4 <li class="tab_hotel" attr="read">閱讀</li>
5 <li class="tab_hotel" attr="comment">評論</li>
6 </ul>
1 events: {
2 'click #sort': function (e) {
3 var el = $(e.target);
4 var sort = el.attr('attr');
5
6 var s = '';
7 }
8 },
events: {
'click #sort': function (e) {
var el = $(e.target);
var type = el.attr('attr');
this.list.setComparator(type);
this.list.sort();
},
//list新增方法
setComparator: function (type) {
this.comparator = function (item) {
return Math.max(item.attributes[type]);
這個時候在初始化時候再注冊一個事件
this.listenTo(this.list, 'all', this.render);
于是就能點選不同的标簽按不同的倒叙排列,這裡注意一點是每次改變都會觸發list的all事件(其實應該是reset),完了觸發view的render重新渲染了下資料
完整代碼
這裡對集合的操作暫時到此,對model的操作仍然沒有涉及,我們先引入路由再說吧
Control-引入路由
MVC中View的代碼量可能很大,但是Control的代碼往往才是核心,他全局觀察着整個程式的運作,但是這裡卻給他換了個名字——路由
其實這個名字比較靠譜,Backbone中的控制器其實就是充當了路由的角色
路由的效果
現在我們還沒看源碼,不知道其實作細節,但是實作表現是這樣的:
http://www.example.com/#/state1
http://www.example.com/#/state2
這裡state1,和state2便是不同的View了,以我們這個例子來說,如果index是首頁清單視圖,detail便是某一篇部落格的視圖了,是以
http://www.example.com/#/index——首頁清單
http://www.example.com/#/detail——具體部落格
這個是路由的基本功能,想一想,假如,我們現在各個View已經寫開了,view與view直接資料可以由localstorage通信
但是全局性各個狀态,全局共用方法還得放到控制器裡面,這裡對應的就是路由裡面(比如我一個全局的showLoading方法)
說了這麼多也沒意義,我們先将detail的view做了,再看他是怎麼路由的
切換視圖
其實這個代碼,我處理的的有問題,我們上面的清單中的每一個清單項其實應該對應一個model
我在過程中卻将model與dom的映射關系給丢了,比如我現在點選一個清單項,我需要知道我現在對應的是哪一個model
這裡補救方案是給dom上增加一個索引index,點選時候根據index擷取目前索引,但是這不是長久之計,後面需要更好的辦法
1 for (var i = 0, len = models.length; i < len; i++) {
2 models[i].index = i;
3 html += this.itemTmpt(_.extend(models[i].toJSON(), {index: i}));
4 }
于是我們每一個dom上面就會多出一個index的屬性,哎,這裡感覺不是太好啊
現在點選各個清單後會給相關model增加一個model的屬性:
然後我們這裡初略的重新渲染下頁面,這裡稍微修改下代碼:
完整的代碼
這個代碼裡面,我們點選其中一個list-item就會顯示我們部落格正文,但是問題馬上就來了
現在的問題
做到現在我們程式大概的邏輯也出來了,當然,問題也出來了:
① 我從首頁來到了部落格頁,但是大哥,我該怎麼回去啊???
② 我們的程式全部在demo這個頁面裡面,個人感覺很亂啊!!!現在是兩個view就這樣,萬一我有20個view我是不是要哭!!!
③ 我們最開始的view時index的,比如上面的回退按鈕與“部落格園”三個字,我們在部落格頁整個view應該隸屬于自己的,但是這是嵌套的,很亂
要解決以上問題,我覺得是時候引入require已經路由的知識點了
require這個庫,我們後面有時間在一起深入學習下,這裡隻是使用其核心的功能,簡單起見,模闆我就全部寫在demo中,不予分離了
引入路由功能
我們當然想在頁面中點選某個按鈕來導向某個方法了,比如我們上面進入了detail部落格頁,我現在先回到首頁,我可以後退
1 var App = Backbone.Router.extend({
2 routes: {
3 "": "index", // #index
4 "index": "index", // #index
5 "detail": "detail" // #detail
6 },
7 index: function () {
8 var index = new Index();
9 }
10 });
11
12 var app = new App();
13 Backbone.history.start();
這麼小心一段代碼加上後,就會在頁面url錨點#後面的字元變了後執行相關的方法,顯然我們這裡需要更多的資訊,或者說,我們的路由應該擔任整個view通信的功能
首先,我們這裡将index與detail兩個view的模闆完全獨立,這裡用了比較圖的辦法,全部清除html,但是現在确實可以跳轉了
View Code
現在問題又來了,我點選其中一個一個清單項目時候,我就執行了render方法,現在我不想這麼做了,我想将其加載資料的邏輯放到detail裡面去
并且通過路由的方式實作,但是我們資料model的傳遞(這裡沒有使用localstorage)需要用路由來實作
重要版本
如此一來,我們的基本邏輯結束,馬上我們又面臨其它問題:
① 我們每個view的initialize方法都會被傳入app接口
② 我們每個view都有一些重複的代碼(比如this.app = app),而我們各個view沒有好的狀态控制
比如我們頁面的create階段,load階段,show階段,hide階段,這些都需要事件進行處理,這裡卻沒法一一關注
③ 可以看到,我們的路由居然還充當了很多傳遞資料的作用,但是我們并不應該這樣寫
④ 各位是否感覺我們的路由仍然太簡陋,我們的程式很容易報錯呢?
以上這些問題暫時留給各位思考,我下次使用require将我們的view分離先,本來今天想做的,但是感覺幹不動了
結語
今天的内容暫時到此,本來想做個簡單的例子來着,結果做着做着居然又涉及到這麼多東西了,我們下次将這個單頁應用完成,并且開始源碼學習:
① 細化App(路由/控制器),讓其完成更多的工作
② 引入require分離view
③ 建立view父類供各個view使用
④ 源碼細節實作分析
總的來說,Backbone的閱讀應該比原來碰到的架構難,原來那些架構隻不過是基礎庫,但是Backbone涉及到了思想
這種架構性東西,我們後面還得花大力氣消化,今天暫時到此
本文轉自葉小钗部落格園部落格,原文連結:http://www.cnblogs.com/yexiaochai/p/3486173.html,如需轉載請自行聯系原作者