【再探backbone 03】博客園單頁應用實例(提供源碼)

前言

以前嘗試性的讀了下backbone的源碼,對繼承、事件、view一塊還比較熟悉,看下去比較順暢,可是在model collection方面就很不順利javascript

究其緣由仍是沒有使用過,不夠熟悉,以碼讀碼,脫離了業務邏輯的代碼毫無心義,因此今天咱們先來作一個例子吧,而後再根據例子學習css

今天來一段官網之外的代碼,原本這裏想抄一個代碼來着,可是這樣的話好像意義就不大了,因而本身從新寫一個例子吧html

注意這個例子只是簡單例子,各位不要當真,並且代碼是今天下午寫的,有BUG不要罵我,而後放到IIS環境下才有數據java

下載源碼:02backbone.zipjquery

單頁應用實例

以博客園爲例,咱們一塊兒作一個單頁,提供list和detail兩個頁面,而且爲list提供分頁和簡單篩選功能來鞏固咱們的backbone學習json

文件結構

首先爲了簡單起見,咱們這裏目錄暫時以下:服務器

其中css樣式是上次作單頁應用研究剩下的,此次直接拿來用吧app

數據源

而後,咱們來簡單看看咱們博客園的數據源返回的數據:框架

很遺憾博客園暫時只提供了xml的返回格式,其中我本身作了json的解析,其實就算我本身不作解析,也能夠經過model的parse作解析dom

可是我沒有那麼蛋疼,這裏仍是使用後臺方法解析吧

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代碼:

  1 <!DOCTYPE html>
  2 <html xmlns="http://www.w3.org/1999/xhtml">
  3 <head>
  4   <meta charset="utf-8" />
  5   <title></title>
  6   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  7   <link rel="Stylesheet" type="text/css" href="res/style/main2.css" />
  8   <link rel="Stylesheet" type="text/css" href="res/style/tuan.css" />
  9   <style> .pro_list_rank { margin: 5px 0; padding-right: 22px; }
 10     .figcaption span { text-align: center; }
 11     .blog_item {}
 12     .blog_item img { width: 48px; height; 48px; margin: 4px; padding: 1px; float: left; border: 1px solid #CCC;  }
 13     
 14     .blog_item .item_footer { color: #757575; font-size: 0.86em; }
 15     a { color:  #005A94; }
 16     .tab_hotel { border-left: 1px solid #2B97E2; }
 17     .cont_wrap .content { background-color: White; padding: 5px 10px; }
 18     img { max-width: 98%; }</style>
 19 </head>
 20 <body>
 21   <div class="main-frame">
 22     <div class="main-viewport">
 23       <header>
 24         <b class="icon_home i_bef" id="js_home"></b>
 25         <h1>
 26          博客園</h1>
 27         <i id="js_return" class="returnico"></i>
 28       </header>
 29       <section class="cont_wrap" >
 30         <ul class="pro_list" id="lstbox">
 31         </ul>
 32       </section>
 33       <ul class="tab_search fix_bottom">
 34         <li class="tabcrt">時間</li>
 35         <li class="tab_hotel ">推薦</li>
 36         <li class="tab_hotel ">閱讀</li>
 37         <li class="tab_hotel ">評論</li>
 38       </ul>
 39     </div>
 40   </div>
 41 <script type="text/template" id="item-template">
 42   <li class="arr_r orderItem" data-id="<%=id %>">
 43   <article class="blog_item">
 44     <h3>
 45       <a href="<%=link.href %>" target="_blank">
 46         <%=title.value || '無題' %></a>
 47     </h3>
 48     <div class="author pro_list_rank">
 49       <%if(author.avatar){ %>
 50       <a href="<%=author.uri %>" target="_blank">
 51         <img src="<%=author.avatar %>">
 52       </a>
 53       <%} %>
 54       <%=summary.value %>
 55     </div>
 56     <div class="item_footer">
 57       <a href="<%=author.uri %>" class="lightblue">Scut</a>
 58       <%=published %>
 59       <a href="<%=link.href %>" title="2013-08-21 15:21" class="gray">評論(<%=comments %>)</a>
 60       <a href="<%=link.href %>" class="gray">閱讀(<%=views %>)</a> <span class="price1">推薦(<%=diggs %>)</span></div>
 61   </article>
 62 </li>
 63 </script>
 64   <script src="libs/jquery.js" type="text/javascript"></script>
 65   <script src="libs/underscore.js" type="text/javascript"></script>
 66   <script src="libs/backbone.js" type="text/javascript"></script>
 67   <script type="text/javascript" src="libs/backbone.localStorage.js"></script>
 68   <script type="text/javascript">
 69     //博客模型
 70     var PostModel = Backbone.Model.extend({
 71 
 72     });
 73 
 74     //模型集合
 75     var PostList = Backbone.Collection.extend({
 76       model: PostModel,
 77       parse: function (data) {
 78         // 'data' contains the raw JSON object
 79         return (data && data.feed && data.feed.entry) || {}
 80       }
 81     });
 82 
 83 var View = Backbone.View.extend({
 84   template: _.template($('#item-template').html()),
 85   initialize: function () {
 86     var scope = this;
 87     var curpage = 1;
 88     var pageSize = 10;
 89     this.list = new PostList();
 90     this.list.url = 'Handler.ashx?url=http://wcf.open.cnblogs.com/blog/sitehome/paged/' + curpage + '/' + pageSize;
 91     this.list.fetch({
 92       success: function () {
 93         scope.render();
 94       }
 95     });
 96     this.wrapper = $('#lstbox');
 97   },
 98   render: function () {
 99     var models = this.list.models;
100     var html = '';
101     for (var i = 0, len = models.length; i < len; i++) {
102       html += this.template(models[i].toJSON());
103 
104     }
105     this.wrapper.html(html);
106     var s = '';
107   }
108 });
109 
110     var view = new View();
111     var s = '';
112 
113   </script>
114 </body>
115 </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從新渲染了下數據

  1 <!DOCTYPE html>
  2 <html xmlns="http://www.w3.org/1999/xhtml">
  3 <head>
  4   <meta charset="utf-8" />
  5   <title></title>
  6   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  7   <link rel="Stylesheet" type="text/css" href="res/style/main2.css" />
  8   <link rel="Stylesheet" type="text/css" href="res/style/tuan.css" />
  9   <style> .pro_list_rank { margin: 5px 0; padding-right: 22px; }
 10     .figcaption span { text-align: center; }
 11     .blog_item {}
 12     .blog_item img { width: 48px; height; 48px; margin: 4px; padding: 1px; float: left; border: 1px solid #CCC;  }
 13     
 14     .blog_item .item_footer { color: #757575; font-size: 0.86em; }
 15     a { color:  #005A94; }
 16     .tab_hotel { border-left: 1px solid #2B97E2; }
 17     .cont_wrap .content { background-color: White; padding: 5px 10px; }
 18     img { max-width: 98%; }</style>
 19 </head>
 20 <body>
 21   <div class="main-frame">
 22     <div class="main-viewport" id="main-viewport">
 23     </div>
 24   </div>
 25   <script type="text/template" id="index-template">
 26   <header>
 27     <b class="icon_home i_bef" id="js_home"></b>
 28     <h1>
 29       博客園</h1>
 30     <i id="js_return" class="returnico"></i>
 31   </header>
 32   <section class="cont_wrap">
 33     <ul class="pro_list" id="lstbox">
 34     </ul>
 35   </section>
 36   <ul class="tab_search fix_bottom" id="sort">
 37     <li class="tabcrt" attr="updated">時間</li>
 38     <li class="tab_hotel" attr="diggs">推薦</li>
 39     <li class="tab_hotel" attr="views">閱讀</li>
 40     <li class="tab_hotel" attr="comments">評論</li>
 41   </ul>
 42   </script>
 43   <script type="text/template" id="item-template">
 44   <li class="arr_r orderItem" data-id="<%=id %>">
 45   <article class="blog_item">
 46     <h3>
 47       <a href="<%=link.href %>" target="_blank">
 48         <%=title.value || '無題' %></a>
 49     </h3>
 50     <div class="author pro_list_rank">
 51       <%if(author.avatar){ %>
 52       <a href="<%=author.uri %>" target="_blank">
 53         <img src="<%=author.avatar %>">
 54       </a>
 55       <%} %>
 56       <%=summary.value %>
 57     </div>
 58     <div class="item_footer">
 59       <a href="<%=author.uri %>" class="lightblue">Scut</a>
 60       <%=published %>
 61       <a href="<%=link.href %>" title="2013-08-21 15:21" class="gray">評論(<%=comments %>)</a>
 62       <a href="<%=link.href %>" class="gray">閱讀(<%=views %>)</a> <span class="price1">推薦(<%=diggs %>)</span></div>
 63   </article>
 64 </li>
 65 </script>
 66   <script src="libs/jquery.js" type="text/javascript"></script>
 67   <script src="libs/underscore.js" type="text/javascript"></script>
 68   <script src="libs/backbone.js" type="text/javascript"></script>
 69   <script type="text/javascript" src="libs/backbone.localStorage.js"></script>
 70   <script type="text/javascript">
 71     //博客模型
 72     var PostModel = Backbone.Model.extend({
 73 
 74     });
 75 
 76     //模型集合
 77     var PostList = Backbone.Collection.extend({
 78       model: PostModel,
 79       parse: function (data) {
 80         // 'data' contains the raw JSON object
 81         return (data && data.feed && data.feed.entry) || {}
 82       },
 83       setComparator: function (type) {
 84         this.comparator = function (item) {
 85           return Math.max(item.attributes[type]);
 86         }
 87       }
 88     });
 89 
 90     var View = Backbone.View.extend({
 91       el: $('#main-viewport'),
 92       template: _.template($('#index-template').html()),
 93       itemTmpt: _.template($('#item-template').html()),
 94 
 95       events: {
 96         'click #sort': function (e) {
 97           var el = $(e.target);
 98           var type = el.attr('attr');
 99           this.list.setComparator(type);
100           this.list.sort();
101         }
102       },
103       initialize: function () {
104         //先生成框架html
105         this.$el.html(this.template());
106 
107         var scope = this;
108         var curpage = 1;
109         var pageSize = 10;
110         this.list = new PostList();
111         this.list.url = 'Handler.ashx?url=http://wcf.open.cnblogs.com/blog/sitehome/paged/' + curpage + '/' + pageSize;
112         this.list.fetch({
113           success: function () {
114             scope.render();
115           }
116         });
117         this.wrapper = $('#lstbox');
118 
119         this.listenTo(this.list, 'all', this.render);
120 
121       },
122       render: function () {
123 
124         var models = this.list.models;
125         var html = '';
126         for (var i = 0, len = models.length; i < len; i++) {
127           html += this.itemTmpt(models[i].toJSON());
128         }
129         this.wrapper.html(html);
130         var s = '';
131       }
132     });
133 
134     var view = new View();
135     var s = '';
136 
137   </script>
138 </body>
139 </html>
完整代碼

這裏對集合的操做暫時到此,對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的屬性:

而後咱們這裏初略的從新渲染下頁面,這裏稍微修改下代碼:

  1 <!DOCTYPE html>
  2 <html xmlns="http://www.w3.org/1999/xhtml">
  3 <head>
  4   <meta charset="utf-8" />
  5   <title></title>
  6   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  7   <link rel="Stylesheet" type="text/css" href="res/style/main2.css" />
  8   <link rel="Stylesheet" type="text/css" href="res/style/tuan.css" />
  9   <style> .pro_list_rank { margin: 5px 0; padding-right: 22px; }
 10     .figcaption span { text-align: center; }
 11     .blog_item {}
 12     .blog_item img { width: 48px; height; 48px; margin: 4px; padding: 1px; float: left; border: 1px solid #CCC;  }
 13     
 14     .blog_item .item_footer { color: #757575; font-size: 0.86em; }
 15     a { color:  #005A94; }
 16     .tab_hotel { border-left: 1px solid #2B97E2; }
 17     .cont_wrap .content { background-color: White; padding: 5px 10px; }
 18     img { max-width: 98%; }</style>
 19 </head>
 20 <body>
 21   <div class="main-frame">
 22     <div class="main-viewport" id="main-viewport">
 23     </div>
 24   </div>
 25   <script type="text/template" id="index-template">
 26   <header>
 27     <b class="icon_home i_bef" id="js_home"></b>
 28     <h1>
 29       博客園</h1>
 30     <i id="js_return" class="returnico"></i>
 31   </header>
 32   <section class="cont_wrap">
 33     <div id="post"></div>
 34     <ul class="pro_list" id="lstbox">
 35     </ul>
 36   </section>
 37   <ul class="tab_search fix_bottom" id="sort">
 38     <li class="tabcrt" attr="updated">時間</li>
 39     <li class="tab_hotel" attr="diggs">推薦</li>
 40     <li class="tab_hotel" attr="views">閱讀</li>
 41     <li class="tab_hotel" attr="comments">評論</li>
 42   </ul>
 43   </script>
 44   <script type="text/template" id="item-template">
 45   <li class="arr_r orderItem" data-id="<%=id %>" data-index = "<%=index %>">
 46   <article class="blog_item">
 47     <h3>
 48       <a href="<%=link.href %>" target="_blank">
 49         <%=title.value || '無題' %></a>
 50     </h3>
 51     <div class="author pro_list_rank">
 52       <%if(author.avatar){ %>
 53       <a href="<%=author.uri %>" target="_blank">
 54         <img src="<%=author.avatar %>">
 55       </a>
 56       <%} %>
 57       <%=summary.value %>
 58     </div>
 59     <div class="item_footer">
 60       <a href="<%=author.uri %>" class="lightblue">Scut</a>
 61       <%=published %>
 62       <a href="<%=link.href %>" title="2013-08-21 15:21" class="gray">評論(<%=comments %>)</a>
 63       <a href="<%=link.href %>" class="gray">閱讀(<%=views %>)</a> <span class="price1">推薦(<%=diggs %>)</span></div>
 64   </article>
 65 </li>
 66 </script>
 67   <script type="text/template" id="detail-template">
 68 <section class="cont_wrap" >
 69   <article class="content">
 70           <h1>
 71               <a href="#"><%=title.value %></a></h1>
 72               <div style=" text-align: right; ">
 73               <time pubdate="pubdate" value="2013-04-15"><%=published %></time><br /><span>閱讀(<%=views %>)
 74                   評論(<%=comments %></span>
 75               </div>
 76       <p><%=value %></p>
 77   </article>
 78 </section>
 79 </script>
 80   <script src="libs/jquery.js" type="text/javascript"></script>
 81   <script src="libs/underscore.js" type="text/javascript"></script>
 82   <script src="libs/backbone.js" type="text/javascript"></script>
 83   <script type="text/javascript" src="libs/backbone.localStorage.js"></script>
 84   <script type="text/javascript">
 85     //博客模型
 86     var PostModel = Backbone.Model.extend({
 87 
 88     });
 89 
 90     //模型集合
 91     var PostList = Backbone.Collection.extend({
 92       model: PostModel,
 93       parse: function (data) {
 94         // 'data' contains the raw JSON object
 95         return (data && data.feed && data.feed.entry) || {}
 96       },
 97       setComparator: function (type) {
 98         this.comparator = function (item) {
 99           return Math.max(item.attributes[type]);
100         }
101       }
102     });
103 
104     var Detail = Backbone.View.extend({
105       template: _.template($('#detail-template').html()),
106       initialize: function () {
107 
108       },
109       render: function () {
110         this.$el.html(this.template(this.model.toJSON()));
111         return this;
112       },
113       events: {
114         'click #js_return': function () {
115           window.reload();
116         }
117       }
118     });
119 
120     var Index = Backbone.View.extend({
121       el: $('#main-viewport'),
122       template: _.template($('#index-template').html()),
123       itemTmpt: _.template($('#item-template').html()),
124 
125       events: {
126         'click #sort': function (e) {
127           var el = $(e.target);
128           var type = el.attr('attr');
129           this.list.setComparator(type);
130           this.list.sort();
131         },
132         'click .orderItem': function (e) {
133           var el = $(e.currentTarget);
134           var id = el.attr('data-id');
135           var index = el.attr('data-index');
136           var model = this.list.models[index];
137           var scope = this;
138           var param = { url: 'http://wcf.open.cnblogs.com/blog/post/body/' + id }
139           $.get('Handler.ashx', param, function (data) {
140             (typeof data === 'string') && (data = $.parseJSON(data));
141             if (data && data.string) {
142               //此處將content內容寫入model
143               model.set('value', data.string.value);
144 
145               var d = new Detail();
146               d.model = model;
147               scope.wrapper.hide();
148               scope.post.append(d.render().el);
149 
150             }
151           });
152 
153 
154           var s = '';
155         }
156       },
157       initialize: function () {
158         //先生成框架html
159         this.$el.html(this.template());
160         this.post = this.$('#post');
161 
162         var scope = this;
163         var curpage = 1;
164         var pageSize = 10;
165         this.list = new PostList();
166         this.list.url = 'Handler.ashx?url=http://wcf.open.cnblogs.com/blog/sitehome/paged/' + curpage + '/' + pageSize;
167         this.list.fetch({
168           success: function () {
169             scope.render();
170           }
171         });
172         this.wrapper = $('#lstbox');
173 
174         this.listenTo(this.list, 'all', this.render);
175 
176       },
177       render: function () {
178 
179         var models = this.list.models;
180         var html = '';
181         for (var i = 0, len = models.length; i < len; i++) {
182           models[i].index = i;
183           html += this.itemTmpt(_.extend(models[i].toJSON(), { index: i }));
184         }
185         this.wrapper.html(html);
186         var s = '';
187       }
188     });
189 
190     var index = new Index();
191 //    var detail 
192 
193 
194     var s = '';
195 
196   </script>
197 </body>
198 </html>
完整的代碼

這個代碼裏面,咱們點擊其中一個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,可是如今確實能夠跳轉了

  1 <!DOCTYPE html>
  2 <html xmlns="http://www.w3.org/1999/xhtml">
  3 <head>
  4   <meta charset="utf-8" />
  5   <title></title>
  6   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  7   <link rel="Stylesheet" type="text/css" href="res/style/main2.css" />
  8   <link rel="Stylesheet" type="text/css" href="res/style/tuan.css" />
  9   <style> .pro_list_rank { margin: 5px 0; padding-right: 22px; }
 10     .figcaption span { text-align: center; }
 11     .blog_item {}
 12     .blog_item img { width: 48px; height; 48px; margin: 4px; padding: 1px; float: left; border: 1px solid #CCC;  }
 13     
 14     .blog_item .item_footer { color: #757575; font-size: 0.86em; }
 15     a { color:  #005A94; }
 16     .tab_hotel { border-left: 1px solid #2B97E2; }
 17     .cont_wrap .content { background-color: White; padding: 5px 10px; }
 18     img { max-width: 98%; }</style>
 19 </head>
 20 <body>
 21   <h1>
 22     <a href="demo.htm#index">index</a>
 23   </h1>
 24   <div class="main-frame">
 25     <div class="main-viewport" id="main-viewport">
 26     </div>
 27   </div>
 28   <script type="text/template" id="index-template">
 29   <header>
 30     <b class="icon_home i_bef" id="js_home"></b>
 31     <h1>
 32       博客園</h1>
 33 
 34     <i id="js_return" class="returnico"></i>
 35   </header>
 36   <section class="cont_wrap">
 37     <div id="post"></div>
 38     <ul class="pro_list" id="lstbox">
 39     </ul>
 40   </section>
 41   <ul class="tab_search fix_bottom" id="sort">
 42     <li class="tabcrt" attr="updated">時間</li>
 43     <li class="tab_hotel" attr="diggs">推薦</li>
 44     <li class="tab_hotel" attr="views">閱讀</li>
 45     <li class="tab_hotel" attr="comments">評論</li>
 46   </ul>
 47   </script>
 48   <script type="text/template" id="item-template">
 49   <li class="arr_r orderItem" data-id="<%=id %>" data-index = "<%=index %>">
 50   <article class="blog_item">
 51     <h3>
 52       <a href="<%=link.href %>" target="_blank">
 53         <%=title.value || '無題' %></a>
 54     </h3>
 55     <div class="author pro_list_rank">
 56       <%if(author.avatar){ %>
 57       <a href="<%=author.uri %>" target="_blank">
 58         <img src="<%=author.avatar %>">
 59       </a>
 60       <%} %>
 61       <%=summary.value %>
 62     </div>
 63     <div class="item_footer">
 64       <a href="<%=author.uri %>" class="lightblue">Scut</a>
 65       <%=published %>
 66       <a href="<%=link.href %>" title="2013-08-21 15:21" class="gray">評論(<%=comments %>)</a>
 67       <a href="<%=link.href %>" class="gray">閱讀(<%=views %>)</a> <span class="price1">推薦(<%=diggs %>)</span></div>
 68   </article>
 69 </li>
 70 </script>
 71   <script type="text/template" id="detail-template">
 72 <section class="cont_wrap" >
 73   <article class="content">
 74           <h1>
 75               <a href="#"><%=title.value %></a></h1>
 76               <div style=" text-align: right; ">
 77               <time pubdate="pubdate" value="2013-04-15"><%=published %></time><br /><span>閱讀(<%=views %>)
 78                   評論(<%=comments %></span>
 79               </div>
 80       <p><%=value %></p>
 81   </article>
 82 </section>
 83 </script>
 84   <script src="libs/jquery.js" type="text/javascript"></script>
 85   <script src="libs/underscore.js" type="text/javascript"></script>
 86   <script src="libs/backbone.js" type="text/javascript"></script>
 87   <script type="text/javascript" src="libs/backbone.localStorage.js"></script>
 88   <script type="text/javascript">
 89     //博客模型
 90     var PostModel = Backbone.Model.extend({
 91 
 92     });
 93 
 94     //模型集合
 95     var PostList = Backbone.Collection.extend({
 96       model: PostModel,
 97       parse: function (data) {
 98         // 'data' contains the raw JSON object
 99         return (data && data.feed && data.feed.entry) || {}
100       },
101       setComparator: function (type) {
102         this.comparator = function (item) {
103           return Math.max(item.attributes[type]);
104         }
105       }
106     });
107 
108     var Detail = Backbone.View.extend({
109       el: $('#main-viewport'),
110       template: _.template($('#index-template').html()),
111       detail: _.template($('#detail-template').html()),
112       initialize: function () {
113         this.$el.html(this.template());
114         this.wrapper = $('#lstbox');
115 
116       },
117       render: function () {
118         this.wrapper.html(this.detail(this.model.toJSON()));
119       },
120       events: {
121         'click #js_return': function () {
122           location.href = "demo.htm";
123         }
124       }
125     });
126 
127     var Index = Backbone.View.extend({
128       el: $('#main-viewport'),
129       template: _.template($('#index-template').html()),
130       itemTmpt: _.template($('#item-template').html()),
131 
132       events: {
133         'click #sort': function (e) {
134           var el = $(e.target);
135           var type = el.attr('attr');
136           this.list.setComparator(type);
137           this.list.sort();
138         },
139         'click .orderItem': function (e) {
140           var el = $(e.currentTarget);
141           var id = el.attr('data-id');
142           var index = el.attr('data-index');
143           var model = this.list.models[index];
144           var scope = this;
145           var param = { url: 'http://wcf.open.cnblogs.com/blog/post/body/' + id }
146           $.get('Handler.ashx', param, function (data) {
147             (typeof data === 'string') && (data = $.parseJSON(data));
148             if (data && data.string) {
149               //此處將content內容寫入model
150               model.set('value', data.string.value);
151               var d = new Detail();
152               d.model = model;
153               d.render();
154             }
155           });
156           var s = '';
157         }
158       },
159       initialize: function () {
160         //先生成框架html
161         this.$el.html(this.template());
162         this.post = this.$('#post');
163 
164         var scope = this;
165         var curpage = 1;
166         var pageSize = 10;
167         this.list = new PostList();
168         this.list.url = 'Handler.ashx?url=http://wcf.open.cnblogs.com/blog/sitehome/paged/' + curpage + '/' + pageSize;
169         this.list.fetch({
170           success: function () {
171             scope.render();
172           }
173         });
174         this.wrapper = $('#lstbox');
175 
176         this.listenTo(this.list, 'all', this.render);
177 
178       },
179       render: function () {
180 
181         var models = this.list.models;
182         var html = '';
183         for (var i = 0, len = models.length; i < len; i++) {
184           models[i].index = i;
185           html += this.itemTmpt(_.extend(models[i].toJSON(), { index: i }));
186         }
187         this.wrapper.html(html);
188         var s = '';
189       }
190     });
191 
192     //    var index = new Index();
193     //    var detail
194 
195     var App = Backbone.Router.extend({
196       routes: {
197         "": "index",    // #index
198         "index": "index",    // #index
199         "detail": "detail"    // #detail
200       },
201       index: function () {
202         var index = new Index();
203       }
204     });
205 
206     var app = new App();
207     Backbone.history.start();
208 
209     var s = '';
210 
211   </script>
212 </body>
213 </html>
View Code

如今問題又來了,我點擊其中一個一個列表項目時候,我就執行了render方法,如今我不想這麼作了,我想將其加載數據的邏輯放到detail裏面去

而且經過路由的方式實現,可是咱們數據model的傳遞(這裏沒有使用localstorage)須要用路由來實現

  1 <!DOCTYPE html>
  2 <html xmlns="http://www.w3.org/1999/xhtml">
  3 <head>
  4   <meta charset="utf-8" />
  5   <title></title>
  6   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  7   <link rel="Stylesheet" type="text/css" href="res/style/main2.css" />
  8   <link rel="Stylesheet" type="text/css" href="res/style/tuan.css" />
  9   <style> .pro_list_rank { margin: 5px 0; padding-right: 22px; }
 10     .figcaption span { text-align: center; }
 11     .blog_item {}
 12     .blog_item img { width: 48px; height; 48px; margin: 4px; padding: 1px; float: left; border: 1px solid #CCC;  }
 13     
 14     .blog_item .item_footer { color: #757575; font-size: 0.86em; }
 15     a { color:  #005A94; }
 16     .tab_hotel { border-left: 1px solid #2B97E2; }
 17     .cont_wrap .content { background-color: White; padding: 5px 10px; }
 18     img { max-width: 98%; }</style>
 19 </head>
 20 <body>
 21   <div class="main-frame">
 22     <div class="main-viewport" id="main-viewport">
 23     </div>
 24   </div>
 25   <script type="text/template" id="index-template">
 26   <header>
 27     <b class="icon_home i_bef" id="js_home"></b>
 28     <h1>
 29       博客園</h1>
 30 
 31     <i id="js_return" class="returnico"></i>
 32   </header>
 33   <section class="cont_wrap">
 34     <div id="post"></div>
 35     <ul class="pro_list" id="lstbox">
 36     </ul>
 37   </section>
 38   <ul class="tab_search fix_bottom" id="sort">
 39     <li class="tabcrt" attr="updated">時間</li>
 40     <li class="tab_hotel" attr="diggs">推薦</li>
 41     <li class="tab_hotel" attr="views">閱讀</li>
 42     <li class="tab_hotel" attr="comments">評論</li>
 43   </ul>
 44   </script>
 45   <script type="text/template" id="item-template">
 46   <li class="arr_r orderItem" data-id="<%=id %>" data-index = "<%=index %>">
 47   <article class="blog_item">
 48     <h3>
 49       <a href="<%=link.href %>" target="_blank">
 50         <%=title.value || '無題' %></a>
 51     </h3>
 52     <div class="author pro_list_rank">
 53       <%if(author.avatar){ %>
 54       <a href="<%=author.uri %>" target="_blank">
 55         <img src="<%=author.avatar %>">
 56       </a>
 57       <%} %>
 58       <%=summary.value %>
 59     </div>
 60     <div class="item_footer">
 61       <a href="<%=author.uri %>" class="lightblue">Scut</a>
 62       <%=published %>
 63       <a href="<%=link.href %>" title="2013-08-21 15:21" class="gray">評論(<%=comments %>)</a>
 64       <a href="<%=link.href %>" class="gray">閱讀(<%=views %>)</a> <span class="price1">推薦(<%=diggs %>)</span></div>
 65   </article>
 66 </li>
 67 </script>
 68   <script type="text/template" id="detail-template">
 69 <section class="cont_wrap" >
 70   <article class="content">
 71           <h1>
 72               <a href="#"><%=title.value %></a></h1>
 73               <div style=" text-align: right; ">
 74               <time pubdate="pubdate" value="2013-04-15"><%=published %></time><br /><span>閱讀(<%=views %>)
 75                   評論(<%=comments %></span>
 76               </div>
 77       <p><%=value %></p>
 78   </article>
 79 </section>
 80 </script>
 81   <script src="libs/jquery.js" type="text/javascript"></script>
 82   <script src="libs/underscore.js" type="text/javascript"></script>
 83   <script src="libs/backbone.js" type="text/javascript"></script>
 84   <script type="text/javascript" src="libs/backbone.localStorage.js"></script>
 85   <script type="text/javascript">
 86     //博客模型
 87     var PostModel = Backbone.Model.extend({
 88 
 89     });
 90 
 91     //模型集合
 92     var PostList = Backbone.Collection.extend({
 93       model: PostModel,
 94       parse: function (data) {
 95         // 'data' contains the raw JSON object
 96         return (data && data.feed && data.feed.entry) || {}
 97       },
 98       setComparator: function (type) {
 99         this.comparator = function (item) {
100           return Math.max(item.attributes[type]);
101         }
102       }
103     });
104 
105     var Detail = Backbone.View.extend({
106       el: $('#main-viewport'),
107       template: _.template($('#index-template').html()),
108       detail: _.template($('#detail-template').html()),
109       initialize: function (app) {
110         this.app = app;
111         this.$el.html(this.template());
112         this.wrapper = $('#lstbox');
113         this.render();
114       },
115       render: function () {
116         var scope = this;
117         var id = this.app.id;
118 
119         var param = { url: 'http://wcf.open.cnblogs.com/blog/post/body/' + id }
120 
121         var model = this.app.model;
122 
123         $.get('Handler.ashx', param, function (data) {
124           (typeof data === 'string') && (data = $.parseJSON(data));
125           if (data && data.string) {
126             //此處將content內容寫入model
127             model.set('value', data.string.value);
128             scope.wrapper.html(scope.detail(model.toJSON()));
129           }
130         });
131 
132       },
133       events: {
134         'click #js_return': function () {
135           this.app.forward('index')
136         }
137       }
138     });
139 
140     var Index = Backbone.View.extend({
141       el: $('#main-viewport'),
142       template: _.template($('#index-template').html()),
143       itemTmpt: _.template($('#item-template').html()),
144 
145       events: {
146         'click #sort': function (e) {
147           var el = $(e.target);
148           var type = el.attr('attr');
149           this.list.setComparator(type);
150           this.list.sort();
151         },
152         'click .orderItem': function (e) {
153           var el = $(e.currentTarget);
154           var index = el.attr('data-index');
155           var id = el.attr('data-id');
156           var model = this.list.models[index];
157           this.app.model = model;
158           this.app.id = id;
159 
160 
161           this.app.forward('detail');
162           //          var scope = this;
163           //          var param = { url: 'http://wcf.open.cnblogs.com/blog/post/body/' + id }
164           //          $.get('Handler.ashx', param, function (data) {
165           //            (typeof data === 'string') && (data = $.parseJSON(data));
166           //            if (data && data.string) {
167           //              //此處將content內容寫入model
168           //              model.set('value', data.string.value);
169           //              var d = new Detail();
170           //              d.model = model;
171           //              d.render();
172           //            }
173           //          });
174           //          var s = '';
175         }
176       },
177       initialize: function (app) {
178         this.app = app;
179 
180         //先生成框架html
181         this.$el.html(this.template());
182         this.post = this.$('#post');
183 
184         var scope = this;
185         var curpage = 1;
186         var pageSize = 10;
187         this.list = new PostList();
188         this.list.url = 'Handler.ashx?url=http://wcf.open.cnblogs.com/blog/sitehome/paged/' + curpage + '/' + pageSize;
189         this.list.fetch({
190           success: function () {
191             scope.render();
192           }
193         });
194         this.wrapper = $('#lstbox');
195 
196         this.listenTo(this.list, 'all', this.render);
197 
198       },
199       render: function () {
200 
201         var models = this.list.models;
202         var html = '';
203         for (var i = 0, len = models.length; i < len; i++) {
204           models[i].index = i;
205           html += this.itemTmpt(_.extend(models[i].toJSON(), { index: i }));
206         }
207         this.wrapper.html(html);
208         var s = '';
209       }
210     });
211 
212     //    var index = new Index();
213     //    var detail
214 
215     var App = Backbone.Router.extend({
216       routes: {
217         "": "index",    // #index
218         "index": "index",    // #index
219         "detail": "detail"    // #detail
220       },
221       index: function () {
222         var index = new Index(this.interface);
223 
224       },
225       detail: function () {
226         var detail = new Detail(this.interface);
227 
228       },
229       initialize: function () {
230 
231       },
232       interface: {
233         forward: function (url) {
234           window.location.href = ('#' + url).replace(/^#+/, '#');
235         }
236 
237       }
238 
239 
240     });
241 
242     var app = new App();
243     Backbone.history.start();
244 
245     var s = '';
246 
247   </script>
248 </body>
249 </html>
重要版本

如此一來,咱們的基本邏輯結束,立刻咱們又面臨其它問題:

① 咱們每一個view的initialize方法都會被傳入app接口

② 咱們每一個view都有一些重複的代碼(好比this.app = app),而咱們各個view沒有好的狀態控制

好比咱們頁面的create階段,load階段,show階段,hide階段,這些都須要事件進行處理,這裏卻無法一一關注

③ 能夠看到,咱們的路由竟然還充當了不少傳遞數據的做用,可是咱們並不該該這樣寫

④ 各位是否感受咱們的路由仍然太簡陋,咱們的程序很容易報錯呢?

以上這些問題暫時留給各位思考,我下次使用require將咱們的view分離先,原本今天想作的,可是感受幹不動了

結語

今天的內容暫時到此,原本想作個簡單的例子來着,結果作着作着竟然又涉及到這麼多東西了,咱們下次將這個單頁應用完成,而且開始源碼學習:

① 細化App(路由/控制器),讓其完成更多的工做

② 引入require分離view

③ 建立view父類供各個view使用

④ 源碼細節實現分析

總的來講,Backbone的閱讀應該比原來碰到的框架難,原來那些框架只不過是基礎庫,可是Backbone涉及到了思想

這種框架性東西,咱們後面還得花大力氣消化,今天暫時到此

相關文章
相關標籤/搜索