以前嘗試性的讀了下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會本身對應
咱們知道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 = ''; } });
須要注意一點是這裏是異步的,因此不要傻傻的立刻想在後面操做數據
如今數據模型與集合都有了,咱們須要一個承載他的頁面,因而咱們先隨便搞下將數據顯示出來:
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>
這是咱們以前使用過的數據模板,這裏直接搞過來使用了
並在集合數據加載結束調用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 });
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>
到如今爲止,咱們只是簡單將視圖展現了出來,如今咱們來多用一點集合與模型的操做,深刻以前的學習
這裏又有個比較遺憾的地方就是,咱們並不須要寫數據到服務器,我這裏也不許備調用寫的接口,因此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的操做仍然沒有涉及,咱們先引入路由再說吧
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>
如今問題又來了,我點擊其中一個一個列表項目時候,我就執行了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涉及到了思想
這種框架性東西,咱們後面還得花大力氣消化,今天暫時到此