zoukankan      html  css  js  c++  java
  • 【再探backbone 03】博客园单页应用实例(提供源码)

    前言

    之前尝试性的读了下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代码:

      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涉及到了思想

    这种框架性东西,我们后面还得花大力气消化,今天暂时到此

  • 相关阅读:
    在日志中记录Java异常信息的正确姿势
    基于Spring Boot架构的前后端完全分离项目API路径问题
    Spring生态简介
    WebSocket协议入门介绍
    Spring Boot程序正确停止的姿势
    python 中 __init__方法
    python中的if __name__ == 'main'
    python 类和实例
    内建模块 datetime使用
    内建模块collections的使用
  • 原文地址:https://www.cnblogs.com/yexiaochai/p/3486173.html
Copyright © 2011-2022 走看看