基于Backbone.js的JavaScript MVC示例程序(4)

3.1 显示User列表

界面如下:

1.html文件

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
 2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 3 <html>
 4 <head>
 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 6 <script src="./js/jquery.js"></script>
 7 <script src="./js/underscore.js"></script>
 8 <script src="./js/backbone.js"></script>
 9 <script src="./js/mvc1.js"></script><!-- 引入js文件 -->
10 <script type="text/template" id="user-item-template"><!-- html模板 -->
11     <span>(<%= id %>)</span><a href="#"><%= username %></a>
12 </script>
13 <link rel="stylesheet" type="text/css" href="./css/default.css" />
14 <title>MVC 1</title>
15 </head>
16 <body>
17     <div id="main">
18         <div id="left">
19             <h3></h3>
20             <ul id="user-list"></ul>
21         </div>
22         <div id="right"></div>
23     </div>
24 </body>
25 </html>

 mvc1.js文件

 1 $(document).ready(function() { //注释一
 2     
 3     //定义User
 4     var User = Backbone.Model.extend({
 5     });
 6     
 7     //定义UserList,是User的集合
 8     var UserList = Backbone.Collection.extend({
 9         model : User,
10         url : "/backbone-sample/rest/user", //注释二
11         /*****重载fetch****
12         fetch : function() {
13             var self = this;
14             $.ajax({
15                 url: self.url,
16                 cache:false,
17                 type: 'GET',
18                 async: true,
19                 dataType: 'json',
20                 timeout: 300000,
21                 success: function( data, textStatus ) {                            
22                     self.reset(data.user);
23                 },        
24             });
25         }
26         *************/
27     });
28     
29     //定义UserItemView,用来显示用户列表中的一个条目
30     var UserItemView = Backbone.View.extend({
31         tagName : "li",
32         userItemTemplate : _.template($("#user-item-template").html()), //绑定模板
33         render : function() {
34             this.$el.html(this.userItemTemplate(this.model.toJSON()));
35             return this;
36         },
37     });
38     
39     //定义UserListView,用来显示用户列表
40     var UserListView = Backbone.View.extend({
41         el : $("#main"),
42         initialize : function() {
43             this.userList = new UserList();
44             this.userList.bind('reset', this.addAll, this);
45             this.userList.bind('all', this.render, this); //注释三
46             this.userList.fetch({silent: true, success:function(collection, response){ //注释四
47                 if(response != null){
48                     collection.reset(response.user);
49                 }else{
50                     userListView.render();
51                 }
52             }});
53         },
54         render : function() {
55             this.$("#left h3").html("Total Number:"+this.userList.length);
56         },
57         addOne : function(user) {
58             var view = new UserItemView({model : user});
59             this.$("#user-list").append(view.render().el);
60         },
61         addAll : function() { 
62             this.userList.each(this.addOne);
63         },
64     });
65     
66     var userListView = new UserListView();//注释五
67 });

 注释一:

一开始列表内容显示不出来,找了半天没找到原因,后来才发现是忘记加document.ready了。

注释二:

Model 里面各有一个 url() 方法,和一个 urlRoot 属性;Collection 里面有一个 url() 方法,它们的关系如下:

model.url() 返回模型资源在服务器上位置的相对 URL,默认的的实现是:如果模型包含在某个集合中,则生成 URL 的形式为:"/[collection.url]/[id]"; 如果模型不是集合的一部分,则 URL 形式为:"/[urlRoot]/id"。当然可以自己重载这个方法。

例如:一个 id 为101的模型,存储在url为 "/documents/7/notes" 的 Colletion 中, 那么该模型的 URL 为:"/documents/7/notes/101"。

一般 GET、PUT、DELETE 是对某个特定模型的操作,会用 model.url() 得到带有 id 的模型 URL;而 POST 操作是不知道模型id的,因此会用 collection.url() 得到集合的 URL。

在本例中,User 包含在 UserList 中,因此需要指定 UserList 的 url。

注释三:

官网上对于bind方法的解释:object.bind(event, callback, [context])

绑定 callback 函数到 object 对象。 当事件触发时执行回调函数 callback 。如果一个页面中有大量不同的事件,按照惯例使用冒号指定命名空间:"poll:start"或"change:selection"。当 callback 执行时提供第三个可选参数,可以为 this 指定上下文: model.bind(‘change’, this.render, this)绑定到特殊事件 "all" 的回调函数会在任意事件发生时被触发,其第一个参数为事件的名称。

注意到第三个参数,指定了第二个参数中this所代表的对象,例如:如果把this.userList.bind('add', this.addOne, this)的this去掉,那么实际执行的时候,this.addOne中的this会是userList,实际上应该是userListView,于是就会出错。

还有一点,在Todos这个例子中,所有的事件都是使用on来绑定事件的,也就是this.userList.on('add', this.addOne, this),我试了一下,二者没有什么区别。查了一下源码,on是定义在Backbone.Events中的一个函数,暂时还没能理解为什么二者是等价的。

on: function(events, callback, context) {…} // Bind one or more space separated events, `events`, to a `callback` function. Passing `"all"` will bind the callback to all events fired.

注释四:

官网上对于Collection的fetch函数的解释如下:collection.fetch([options]) 

从服务器拉取集合的默认模型,成功接收数据后会重置(reset)集合。options 支持 success 和 error 回调函数,回调函数接收 (collection, response) 作为参数。 可以委托 Backbone.sync 在随后处理个性化需求。处理 fetch 请求的服务器应当返回模型的 JSON 数组。

也就是调用 UserList 的 fetch() 方法时,会自动对 model.url() 的地址发出GET请求,然后将接收到的 JSON 数组作为参数来调用 reset() 方法自动设置UserList里面的User数组。

在我Server端,返回的Userlist格式如下:

{"user":[{"id":"63","username":"Andy0011","password":"123123","email":"111111@1.com","phone":""},…]}

 注意到最外面会有一个 "user",这样的格式不能被默认的fetch函数使用来给集合设值,因此需要自己重载fetch函数。

有两个方法来实现:

第一个方法是在调用fetch函数的时候使用success回调函数,如注释四 fetch() 中的代码块所示。

注意到有一个 silent: true,这是因为 fetch() 是异步的,当运行完之后自动触发 reset 事件来给 userList 赋值,但是这个时候服务器端的JSON还没有返回来,所以会报错。加上 silent: true 之后,就不会自动触发reset事件了,而是在success回调函数中使用 response.user 作为参数手动调用reset函数来给userList赋值。当然如果数据库里面是空的就会返回空,因此需要判断一下,区分处理。

第二个方法更加灵活了,是在var UserList = Backbone.Collection.extend({ })这个里面重载fetch函数,如11-26行注释中的代码块所示。

这是一个典型的jQuery ajax调用,将请求设置为同步是为了解决上面那个silent: true的问题。

注释五:

需要初始化一个 UserListView 类型的对象,页面显示的流程是:

调用 UserListView 的 initialize() 方法(42行),在其中将2个方法绑定到了 userList 的事件上(44-45行),并调用了 userList 的 fetch() 放来从Server 获取数据并给其赋值(46行),在赋值的时候调用了 userList 的 reset() 方法(48行),这时候会触发已绑定的 "reset" 事件,并调用 UserListView 的 addAll() 方法显示列表内容,同时也会触发 "all" 事件,并调用UserListView 的 render() 方法在列表头部现实列表长度。在 addAll() 方法中为userList中的每一个元素调用 addOne() 方法(57行),在 addOne() 方法中会创建一个 UserItemView 并用它显示列表的一个条目(61行)。

    

原文地址:https://www.cnblogs.com/hiddenfox/p/2646520.html