RequireJS与Backbone简单整合

前言

昨天我们一起学习了Backbone,最后做了一个备忘录的例子,说是做了不如说是看了下官方提供的例子,所以最终我感觉我们还是没能掌握Backbone,今天还得做个其它例子先。

然后前面也只是草草学习了RequireJS,没做demo,这个周末又在看电影打游戏睡觉瞎折腾,转眼就周日下午了,突然诗性大起,于是作诗一首先:

古有通宵看A片,今有彻夜码代码

好吧,我们开始今天的学习吧,我们今天先用backbone做一个通讯录的东西,然后使用requireJS组装之。

部分参考:the5fire的技术博客

简单例子

做之前我们先来个简单的例子:

 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head>
 3     <title></title>
 4 </head>
 5 <body>
 6     <div id="contactapp">
 7         <header>
 8             <h1>
 9                 通讯录</h1>
10         </header>
11         <section id="main">
12             <ul id="contact-list">
13             </ul>
14         </section>
15         <div class="create">
16             <input type="button" value="增加(弹出框)" id="addDia" />
17         </div>
18     </div>
19 </body>
20 <script src="js/jquery.js" type="text/javascript"></script>
21 <script src="js/underscore.js" type="text/javascript"></script>
22 <script src="js/backbone.js" type="text/javascript"></script>
23 <script type="text/javascript">
24     (function ($) {
25         var Contact = Backbone.Model.extend({
26             //创建一个contact对象,拥有name属性
27             name: null
28         });
29         var ContackList = Backbone.Collection.extend({
30             initialize: function (models, options) {
31                 //contact集合
32                 this.bind('add', options.view.addOne);
33             }
34         });
35         var AppView = Backbone.View.extend({
36             el: $('body'),
37             initialize: function () {
38                 //实例化集合,并传入AppView对象
39                 this.contacts = new ContackList(null, { view: this });
40             },
41             events: {
42                 'click #addDia': 'addDia'
43             },
44             addDia: function () {
45                 var name = prompt('请输入姓名');
46                 var c = new Contact({ name: name });
47                 this.contacts.add(c);
48             },
49             addOne: function (model) {
50                 $('#contact-list').append('<li>' + model.get('name') + '</li>');
51             }
52         });
53         var app = new AppView();
54     })(jQuery);
55 </script>
56 </html>

PS:感谢the5fire给出的例子,我和我的小伙伴一下都明白了。。。。

以上代码涉及到Backbone三个部分:View、Model、Collection,我们在addOne里面使用了jquery绑定dom以后会将之消除。

各位请看这个代码:

this.bind('add', options.view.addOne);

在集合中绑定了add事件,在addDia最后执行了,然后触发集合的事件,才最后将dom添加完成。

知识回顾(参考the5fire)

the5fire关于backbone的文章写的很好(http://www.the5fire.com),我们一起来看看顺便回顾下我们的知识。

model

Man = Backbone.Model.extend({
        initialize: function(){
            alert('Hey, you create me!');
        }
    });
var man = new Man;

这个是一个model最简单的model,initialize中的方法一来就会执行,这里就会弹出框:

对象赋值

Man = Backbone.Model.extend({
    initialize: function () {
        alert('Hey, you create me!');
    },
    defaults: {
        name: '张三',
        age: '38'
    }
});
var man = new Man;
alert(man.get('name'));
//man.set({ name: 'the5fire', age: '10' });

若是不赋值就使用默认值,若是赋值则采用给的值。

事件与方法

Man = Backbone.Model.extend({
    initialize: function(){
        alert('Hey, you create me!');
        //初始化时绑定监听
        this.bind("change:name",function(){
            var name = this.get("name");
            alert("你改变了name属性为:" + name);
        });
    },
    defaults: {
        name:'张三',
        age: '38'
    },
    aboutMe: function(){
        return '我叫' + this.get('name') + ',今年' + this.get('age') + '岁';
    }
});
var man = new Man;
man.set({name:'the5fire'})  //触发绑定的change事件,alert。

可以定义方法aboutMe,也可以在initialize中绑定事件以监听某个属性的变化。

验证及错误提示

Man = Backbone.Model.extend({
    initialize: function () {
        this.bind("error", function (model, error) {
            alert(error);
        });
    },
    validate: function (attributes) {
        if (attributes.name == '') {
            return "name不能为空!";
        }
    },
});
var man = new Man;
man.set({ name: '' }); //根据验证规则,弹出错误提示。

此处验证不通过便会触发错误提示。

PS:经测试并没有提示,问题后面跟进

PS:最后证明有反应,我调试页面用错了

对象持久化

对象持久化可以是服务器也可以是本地存储,具体就不展开了。

collection

集合其实就是model的有序集合,经过周末的学习,我们应该比较熟悉了:

Book = Backbone.Model.extend({
    defaults: {    // 感谢网友蓝色动力指正改为defaults
        title: 'default'
    },
    initialize: function () {
        //alert('Hey, you create me!');
    }
});
BookShelf = Backbone.Collection.extend({
    model: Book
});
var book1 = new Book({ title: 'book1' });
var book2 = new Book({ title: 'book2' });
var book3 = new Book({ title: 'book3' });
//var bookShelf = new BookShelf([book1, book2, book3]); 
//注意这里面是数组,或者使用add
var bookShelf = new BookShelf;
bookShelf.add(book1);
bookShelf.add(book2);
bookShelf.add(book3);
bookShelf.remove(book3);
//基于underscore这个js库,还可以使用each的方法获取collection中的数据
bookShelf.each(function (book) {
    alert(book.get('title'));
});

fetch

我们若是要与服务器通讯获取数据,需要先为bookshelf定义url:

bookShelf.fetch({ url: '/getbooks/', success: function (collection, response) {
    collection.each(function (book) {
        alert(book.get('title'));
    });
}, error: function () {
    alert('error');
}
});
//对应的BookShelf的返回格式如下:
[{'title':'book1'},{'title':'book2'}.....]

此后我们需要将页面的dom与数据同步,所以会用到reset事件;

bookShelf.bind('reset',showAllBooks);
showAllBooks = function(){
    bookShelf.each(function(book){
        ​//将book数据渲染到页面。
    });
}
 1 <html>
 2 <head>
 3     <title>the5fire-backbone-collection</title>
 4 </head>
 5 <body>
 6 </body>
 7 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
 8 <script src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.4/underscore-min.js"></script>
 9 <script src="http://ajax.cdnjs.com/ajax/libs/backbone.js/0.3.3/backbone-min.js"></script>
10 <script>
11 (function ($) {
12     //collection是一个简单的models的有序集合
13     //1、一个简单的例子
14 
15     Book = Backbone.Model.extend({
16         defaults : {    // 感谢网友蓝色动力指正改为defaults
17             title:'default'
18         },
19         initialize: function(){
20             //alert('Hey, you create me!');
21         }
22     });
23     BookShelf = Backbone.Collection.extend({
24         model : Book
25     });
26 
27     var book1 = new Book({title : 'book1'});
28     var book2 = new Book({title : 'book2'});
29     var book3 = new Book({title : 'book3'});
30 
31     //var bookShelf = new BookShelf([book1, book2, book3]); //注意这里面是数组,或者使用add
32     var bookShelf = new BookShelf;
33     bookShelf.add(book1);
34     bookShelf.add(book2);
35     bookShelf.add(book3);
36     bookShelf.remove(book3);
37     /*
38     for(var i=0; i<bookShelf.models.length; i++) {
39         alert(bookShelf.models[i].get('title'));
40     }
41     */
42     //基于underscore这个js库,还可以使用each的方法获取collection中的数据
43     bookShelf.each(function(book){
44         alert(book.get('title'));
45     });
46 
47     //2、使用fetch从服务器端获取数据,使用reset渲染
48     bookShelf.bind('reset', showAllBooks);
49     bookShelf.fetch({url:'/getbooks/',success:function(collection,response){
50         collection.each(function(book){
51             alert(book.get('title'));
52         });
53     },error:function(){
54         alert('error');
55     }});
56     showAllBooks = function(){
57         bookShelf.each(function(book){
58 //将book数据渲染到页面。
59         });
60     }
61     //上述代码仅仅均为可正常执行的代码,不过关于服务器端的实例在后面会有。
62 })(jQuery);
63 </script>
64 </html>
完整参考代码

Router(之前好像没看到)

之前我们学习的时候好像错过了Router了,路由的出现是想控制URL呢,Backbone.Router会把#标签当做url路径。

 1 <html>
 2 <head>
 3     <title>the5fire-backbone-router</title>
 4 </head>
 5 <body>
 6     <a href="#/posts/120">Post 120</a>
 7 <a href="#/download/user/images/hey.gif">download gif</a>
 8 <a href="#/dashboard/graph">Load Route/Action View</a>
 9 </body>
10 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
11     <script src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.4/underscore-min.js"></script>
12     <script src="http://documentcloud.github.com/backbone/backbone-min.js"></script>
13     <script>
14     (function ($) {
15         //Backbone中的router,见名知意,router有路由的意思,显然这里是要控制url的。
16         //Backbone.Router会把你连接中的#标签当做是url路径
17         /**
18         //1、来看一个简单的例子
19         var AppRouter = Backbone.Router.extend({
20             routes: {
21                 "*actions" : "defaultRoute"
22             },
23             defaultRoute : function(actions){
24                 alert(actions);
25             }
26         });
27 
28         var app_router = new AppRouter;
29 
30         Backbone.history.start();
31 
32 
33         //2、既然是对url进行匹配那么它应该不仅仅只是简单的静态匹配,应该具有传递参数的功能,所以下面再来一个动态的router的例子.
34         var AppRouter = Backbone.Router.extend({
35             routes: {
36                 "/posts/:id" : "getPost",
37                 "*actions" : "defaultRoute"
38             },
39             getPost: function(id) {
40                 alert(id);
41             },
42             defaultRoute : function(actions){
43                 alert(actions);
44             }
45         });
46 
47         var app_router = new AppRouter;
48 
49         Backbone.history.start();
50         **/
51         //从上面已经可以看到匹配#标签之后内容的方法,有两种:一种是用“:”来把#后面的对应的位置作为参数;还有一种是“*”,它可以匹配所有的url,下面再来演练一下。
52         var AppRouter = Backbone.Router.extend({
53             routes: {
54                 "/posts/:id" : "getPost",
55                 "/download/*path": "downloadFile",  //对应的链接为<a href="#/download/user/images/hey.gif">download gif</a>
56                         "/:route/:action": "loadView",      //对应的链接为<a href="#/dashboard/graph">Load Route/Action View</a>
57                 "*actions" : "defaultRoute"
58             },
59             getPost: function(id) {
60                 alert(id);
61             },
62             defaultRoute : function(actions){
63                 alert(actions);
64             },
65             downloadFile: function( path ){
66                 alert(path); // user/images/hey.gif
67             },
68             loadView: function( route, action ){
69                 alert(route + "_" + action); // dashboard_graph
70             }
71         });
72 
73         var app_router = new AppRouter;
74 
75         Backbone.history.start();
76 
77     })(jQuery);
78     </script>
79 
80 </html>
路由的例子

我们暂时不管这个,否则任务完成不了了。

View

这个看完,我们就要继续今天的学习了,这里用了太多时间啦。

backbone的view是用来显示model数据到页面的,同时监听dom事件并相应变化。

来看看我们的页面主体:

 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head>
 3     <title></title>
 4 </head>
 5 <body>
 6     <div id="search_container">
 7     </div>
 8     <script type="text/template" id="search_template">
 9         <label><%= search_label %></label>
10         <input type="text" id="search_input" />
11         <input type="button" id="search_button" value="Search" />
12     </script>
13 </body>
14 <script src="js/jquery.js" type="text/javascript"></script>
15 <script src="js/underscore.js" type="text/javascript"></script>
16 <script src="js/backbone.js" type="text/javascript"></script>
17 <script type="text/javascript">
18     (function ($) {
19         //此处添加下面的试验代码
20     })(jQuery);
21 </script>
22 </html>

el属性

该属性引用dom中的一些元素,每个view都会有这个属性,没有声明就默认创建空div

(function ($) {
    SearchView = Backbone.View.extend({
        initialize: function () {
            //this.render();
        },
        render: function () {
            //使用underscore这个库,来编译模板
            var template = _.template($("#search_template").html(), {});
            //加载模板到对应的el属性中
            //this.el.html(template);   //感谢 子不语同学指正。
            $(this.el).html(template);
        }
    });
    var searchView = new SearchView({ el: $("#search_container") });
    searchView.render();  //这个reander的方法可以放到view的构造函数中
})(jQuery);

[这里有一个错误,因为这个例子里没有传入search_label这个变量,所以你运行的时候要把html的模板中的那个变量改掉才行。]

事件绑定

(function ($) {
    SearchView = Backbone.View.extend({
        initialize: function () {
            this.render();
        },
        render: function () {
            //使用underscore这个库,来编译模板
            var template = _.template($("#search_template").html(), {});
            //加载模板到对应的el属性中
            //this.el.html(template);
            $(this.el).html(template);
        },
        events: {  //就是在这里绑定的
            'click input[type=button]': 'doSearch'  //定义类型为button的input标签的点击事件,触发函数doSearch
        },

        doSearch: function (event) {
            alert("search for " + $("#search_input").val());
        }
    });
    var searchView = new SearchView({ el: $("#search_container") });
})(jQuery);

模板

此处的模板,就是以数据替换其中的特殊标签<%= search_label %>

 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head>
 3     <title></title>
 4 </head>
 5 <body>
 6     <div id="search_container">
 7     </div>
 8     <script type="text/template" id="search_template">
 9         <label><%= search_label %></label>
10         <input type="text" id="search_input" />
11         <input type="button" id="search_button" value="Search" />
12     </script>
13 </body>
14 <script src="js/jquery.js" type="text/javascript"></script>
15 <script src="js/underscore.js" type="text/javascript"></script>
16 <script src="js/backbone.js" type="text/javascript"></script>
17 <script type="text/javascript">
18     (function ($) {
19         SearchView = Backbone.View.extend({
20             initialize: function () {
21                 this.render('the5fire');
22             },
23             render: function (search_label) {
24                 //使用underscore这个库,来编译模板
25                 var template = _.template($("#search_template").html(), { search_label: search_label });
26                 //加载模板到对应的el属性中
27                 $(this.el).html(template);
28             },
29             events: {  //就是在这里绑定的
30                 'click input[type=button]': 'doChange'
31             },
32             doChange: function (event) {
33                 //通过model发送数据到服务器
34                 this.render('the5fire' + $("#search_input").val());
35             }
36         });
37         var searchView = new SearchView({ el: $("#search_container") });
38     })(jQuery);
39 </script>
40 </html>

阶段总结

好了,知识回顾暂时到这里,我们要来我们的东西了,不然搞不完了。

HTML结构

有点一头雾水的感觉,于是先上一张图吧:

 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head>
 3     <title></title>
 4 </head>
 5 <body>
 6     <div id="contactapp">
 7         <header>
 8             <h1>
 9                 通讯录</h1>
10         </header>
11         <section id="main">
12             <ul id="contact-list">
13             </ul>
14         </section>
15         <div class="create">
16             <label>
17                 姓名:<input type="text" id="name" /></label>
18             <label>
19                 电话:<input type="text" id="phone" /></label>
20             <input type="button" value="保存" id="add" />
21         </div>
22     </div>
23 </body>
24 </html>

下面的输入框用以新建通讯项目,contact-list用以显示通讯录列表。整个页面非常简单,我们先就完成这个功能即可。

模型与集合

完了我们应该创建Contact模型了,我们先来随便写写代码看看有神马情况发生:

var Contact = Backbone.Model.extend({
    validate: function (attr) {
        if (!attr.name || attr.name.length > 5) {
            return '姓名格式错误';
        }
    }
});
var contact = new Contact();
var s = '';

这里根据backbone的Model的extend方法建立了Contact模型。

其中可能会有验证机制,我这里随便写了一个,电话其实也需要验证的。

而模型会有的方法,我们暂时不管他了,先来个集合吧:

<script src="js/underscore.js" type="text/javascript"></script>
<script src="js/backbone.js" type="text/javascript"></script>
<script src="js/backbone.localStorage.js" type="text/javascript"></script>
<script type="text/javascript">
var Contact = Backbone.Model.extend({
    validate: function (attr) {
        if (!attr.name || attr.name.length > 5) {
            return '姓名格式错误';
        }
    }
});

var ContackList = Backbone.Collection.extend({
    model: ContackList,
    localStorage: new Store('contacts')//所有信息保存至contacts空间下,注意此次用到了本地存储的东西
});
var s = '';
</script>

这里使用了本地存储,所以我们必须设置localStorage属性。

视图

现在我们来设置视图后:

 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head>
 3     <title></title>
 4 </head>
 5 <body>
 6     <div id="contactapp">
 7         <header>
 8             <h1>
 9                 通讯录</h1>
10         </header>
11         <section id="main">
12             <ul id="contact-list">
13             </ul>
14         </section>
15         <div class="create">
16             <label>
17                 姓名:<input type="text" id="name" /></label>
18             <label>
19                 电话:<input type="text" id="phone" /></label>
20             <input type="button" value="保存" id="add" />
21         </div>
22     </div>
23 </body>
24 <script src="js/jquery.js" type="text/javascript"></script>
25 <script src="js/underscore.js" type="text/javascript"></script>
26 <script src="js/backbone.js" type="text/javascript"></script>
27 <script src="js/backbone.localStorage.js" type="text/javascript"></script>
28 <script type="text/javascript">
29     (function ($) {
30         var Contact = Backbone.Model.extend({
31             validate: function (attr) {
32                 if (!attr.name || attr.name.length > 5) {
33                     return '姓名格式错误';
34                 }
35             }
36         });
37 
38         var ContackList = Backbone.Collection.extend({
39             model: ContackList,
40             localStorage: new Store('contacts'), //所有信息保存至contacts空间下,注意此次用到了本地存储的东西
41             initialize: function (models, options) {
42                 this.bind('add', options.view.add);
43             }
44         });
45         var AppView = Backbone.View.extend({
46             el: $('body'),
47             tmplate: _.template('<li><%= name %>:<%= phone %></li>'),
48 
49             initialize: function () {
50                 _.bindAll(this, 'save', 'add');
51                 this.contacts = new ContackList(null, { view: this });
52                 this.list = $('#contact-list');
53                 this.name = $('#name');
54                 this.phone = $('#phone');
55             },
56             events: {
57                 'click #add': 'save'
58             },
59             save: function () {
60                 var model = new Contact({ name: this.name.val(), phone: this.phone.val() });
61                 this.contacts.add(model);
62             },
63             add: function (model) {
64                 var obj = model.toJSON();
65                 $(this.list).append(this.tmplate(obj));
66             }
67         });
68         var app = new AppView();
69 
70     })(jQuery);
71 </script>
72 </html>

我们的简单的界面终于出来了。。。。于是我们来优化加功能吧:

  1 <!DOCTYPE html>
  2 <html xmlns="http://www.w3.org/1999/xhtml">
  3 <head>
  4     <title></title>
  5 </head>
  6 <body>
  7     <div id="contactapp">
  8         <header>
  9             <h1>
 10                 通讯录</h1>
 11         </header>
 12         <section id="main">
 13             <ul id="contact-list">
 14             </ul>
 15         </section>
 16         <div class="create">
 17             <label>
 18                 姓名:<input type="text" id="name" /></label>
 19             <label>
 20                 电话:<input type="text" id="phone" /></label>
 21             <input type="button" value="保存" id="add" />
 22         </div>
 23     </div>
 24 </body>
 25 <script src="js/jquery.js" type="text/javascript"></script>
 26 <script src="js/underscore.js" type="text/javascript"></script>
 27 <script src="js/backbone.js" type="text/javascript"></script>
 28 <script src="js/backbone.localStorage.js" type="text/javascript"></script>
 29 <script type="text/javascript">
 30     (function ($) {
 31         var Contact = Backbone.Model.extend({
 32             initialize: function () {
 33                 this.bind("error", function (model, error) {
 34                     alert(error);
 35                 });
 36             },
 37             validate: function (attr) {
 38                 if (attr.name.length == '') {
 39                     return '姓名格式错误';
 40                 }
 41             }
 42         });
 43         var ContactList = Backbone.Collection.extend({
 44             model: Contact,
 45             localStorage: new Store('contacts') //所有信息保存至contacts空间下,注意此次用到了本地存储的东西
 46 
 47         });
 48         var list = new ContactList();
 49         var ContactView = Backbone.View.extend({
 50             tagName: 'li',
 51             template: _.template('<div><%= name %>:<%= phone %></div>'),
 52             events: {
 53                 'click li': 'test'
 54             },
 55             initialize: function () {
 56                 _.bindAll(this, 'render', 'remove');
 57                 this.model.bind('change', this.render);
 58                 this.model.bind('destroy', this.remove);
 59             },
 60             render: function () {
 61                 var html = this.template(this.model.toJSON());
 62                 //this.el是生成的空div
 63                 $(this.el).html(html);
 64                 //返回了当前视图
 65                 return this;
 66             },
 67             remove: function () {
 68                 $(this.el).remove();
 69             },
 70             test: function () {
 71                 alert(this);
 72                 var s = '';
 73             }
 74         });
 75         var AppView = Backbone.View.extend({
 76             el: $('body'),
 77             events: {
 78                 'click #add': 'save'
 79             },
 80             initialize: function () {
 81                 this.name = this.$('#name');
 82                 this.phone = this.$('#phone');
 83                 this.list = this.$('#contact-list');
 84 
 85                 _.bindAll(this, 'render', 'add', 'loadList', 'save');
 86                 //为集合绑定事件
 87                 list.bind('add', this.add);
 88                 //添加修改时触发
 89                 list.bind('refresh', this.loadList);
 90                 list.fetch();
 91             },
 92             //添加项目
 93             add: function (model) {
 94                 var view = new ContactView({ model: model });
 95                 this.list.append(view.render().el);
 96 //                view.model.save({ name: model.name, phone: model.phone });
 97                 var s = '';
 98             },
 99             loadList: function () {
100                 list.each(this.add);
101             },
102             save: function () {
103                 var name = this.name.val();
104                 var phone = this.phone.val();
105                 list.create({ name: name, phone: phone });
106                 this.name.val('');
107                 this.phone.val('');
108             }
109         });
110         var app = new AppView();
111 
112     })(jQuery);
113 </script>
114 </html>

这个代码与上述代码有些不同,我们来理一理:

① 模型与集合变化不大

② 具有2个视图:

通讯录视图,我们后面通讯录会有编辑、删除或者其他功能,就在此上写

全局视图,AppView用于全局,可能还会显示整体状态。

③流程

因为我们只有一个通讯录列表,所以将之全局化出来了:

var list = new ContactList();

ContactView主要关注自身,与整体可以隔离开。

tagName指定了形成的dom的外层结构,不指定就是div

template会解析模板,我直接写到这里了,后面我们做点修改给个删除功能

template: _.template('<div><%= name %>:<%= phone %><a href="javascript:;">[删除]</a></div>'),

events就是绑定的事件

PS:具体代码各位自己看吧......

这里将删除事件加上就算阶段完成了:

  1 <!DOCTYPE html>
  2 <html xmlns="http://www.w3.org/1999/xhtml">
  3 <head>
  4     <title></title>
  5 </head>
  6 <body>
  7     <div id="contactapp">
  8         <header>
  9             <h1>
 10                 通讯录</h1>
 11         </header>
 12         <section id="main">
 13             <ul id="contact-list">
 14             </ul>
 15         </section>
 16         <div class="create">
 17             <label>
 18                 姓名:<input type="text" id="name" /></label>
 19             <label>
 20                 电话:<input type="text" id="phone" /></label>
 21             <input type="button" value="保存" id="add" />
 22         </div>
 23     </div>
 24 </body>
 25 <script src="js/jquery.js" type="text/javascript"></script>
 26 <script src="js/underscore.js" type="text/javascript"></script>
 27 <script src="js/backbone.js" type="text/javascript"></script>
 28 <script src="js/backbone.localStorage.js" type="text/javascript"></script>
 29 <script type="text/javascript">
 30     (function ($) {
 31         var Contact = Backbone.Model.extend({
 32             initialize: function () {
 33                 this.bind("error", function (model, error) {
 34                     alert(error);
 35                 });
 36             },
 37             validate: function (attr) {
 38                 if (attr.name.length == '') {
 39                     return '姓名格式错误';
 40                 }
 41             }
 42         });
 43         var ContactList = Backbone.Collection.extend({
 44             model: Contact,
 45             localStorage: new Store('contacts') //所有信息保存至contacts空间下,注意此次用到了本地存储的东西
 46 
 47         });
 48         var list = new ContactList();
 49         var ContactView = Backbone.View.extend({
 50             tagName: 'li',
 51             template: _.template('<div><%= name %>:<%= phone %><a href="javascript:;" class="delete">[删除]</a></div>'),
 52             events: {
 53                 'click .delete': 'destroy'
 54             },
 55             initialize: function () {
 56                 _.bindAll(this, 'render', 'remove');
 57                 this.model.bind('change', this.render);
 58                 this.model.bind('destroy', this.remove);
 59             },
 60             render: function () {
 61                 var html = this.template(this.model.toJSON());
 62                 //this.el是生成的空div
 63                 $(this.el).html(html);
 64                 //返回了当前视图
 65                 return this;
 66             },
 67             destroy: function () {
 68                 this.model.destroy();
 69             },
 70             remove: function () {
 71                 $(this.el).remove();
 72 
 73             }
 74         });
 75         var AppView = Backbone.View.extend({
 76             el: $('body'),
 77             events: {
 78                 'click #add': 'save'
 79             },
 80             initialize: function () {
 81                 this.name = this.$('#name');
 82                 this.phone = this.$('#phone');
 83                 this.list = this.$('#contact-list');
 84 
 85                 _.bindAll(this, 'render', 'add', 'loadList', 'save');
 86                 //为集合绑定事件
 87                 list.bind('add', this.add);
 88                 //添加修改时触发
 89                 list.bind('refresh', this.loadList);
 90                 list.fetch();
 91             },
 92             //添加项目
 93             add: function (model) {
 94                 var view = new ContactView({ model: model });
 95                 this.list.append(view.render().el);
 96                 //                view.model.save({ name: model.name, phone: model.phone });
 97                 var s = '';
 98             },
 99             loadList: function () {
100                 list.each(this.add);
101             },
102             save: function () {
103                 var name = this.name.val();
104                 var phone = this.phone.val();
105                 list.create({ name: name, phone: phone });
106                 this.name.val('');
107                 this.phone.val('');
108             }
109         });
110         var app = new AppView();
111 
112     })(jQuery);
113 </script>
114 </html>
带删除功能的通讯录

阶段总结

我们又简单的回顾了下backbone,这次学习后我和我的小伙伴表示都懂了。。。。

整合requireJS

先上个图:

尼玛,一下多出了好多文件:

模型

define(function () {
    var Contact = Backbone.Model.extend({
        initialize: function () {
            this.bind("error", function (model, error) {
                alert(error);
            });
        },
        validate: function (attr) {
            if (attr.name.length == '') {
                return '姓名格式错误';
            }
        }
    });
    return Contact;
});

集合

define(['model/contact'], function (Contact) {
    var ContactList = Backbone.Collection.extend({
        model: Contact,
        localStorage: new Store('contacts') //所有信息保存至contacts空间下,注意此次用到了本地存储的东西

    });
    return ContactList;
});

contact视图

define(function () {
    var ContactView = Backbone.View.extend({
        tagName: 'li',
        template: _.template('<div><%= name %>:<%= phone %><a href="javascript:;" class="delete">[删除]</a></div>'),
        events: {
            'click .delete': 'destroy'
        },
        initialize: function () {
            _.bindAll(this, 'render', 'remove');
            this.model.bind('change', this.render);
            this.model.bind('destroy', this.remove);
        },
        render: function () {
            var html = this.template(this.model.toJSON());
            //this.el是生成的空div
            $(this.el).html(html);
            //返回了当前视图
            return this;
        },
        destroy: function () {
            this.model.destroy();
        },
        remove: function () {
            $(this.el).remove();

        }
    });
    return ContactView;
});

全局视图

define(['collection/contact', 'view/contact'], function (contact, ContactView) {
    window.list = new contact();
    var AppView = Backbone.View.extend({
        el: $('body'),
        events: {
            'click #add': 'save'
        },
        initialize: function () {
            this.name = this.$('#name');
            this.phone = this.$('#phone');
            this.list = this.$('#contact-list');

            _.bindAll(this, 'render', 'add', 'loadList', 'save');
            //为集合绑定事件
            list.bind('add', this.add);
            //添加修改时触发
            list.bind('refresh', this.loadList);
            list.fetch();
        },
        //添加项目
        add: function (model) {
            var view = new ContactView({ model: model });
            this.list.append(view.render().el);
            //                view.model.save({ name: model.name, phone: model.phone });
            var s = '';
        },
        loadList: function () {
            list.each(this.add);
        },
        save: function () {
            var name = this.name.val();
            var phone = this.phone.val();
            list.create({ name: name, phone: phone });
            this.name.val('');
            this.phone.val('');
        }
    });
    return AppView;
});

main函数

require.config({
    paths: {
        jquery: 'js/jquery',
        underscore: 'js/underscore',
        backbone: 'js/backbone',
        bl: 'js/backbone.localStorage'

    }
});

require(['jquery', 'underscore', 'backbone', 'bl', 'model/contact', 'collection/contact', 'view/contact', 'view/app'], 
function ($, _, b, bl, model, collection, view, app) {
    var app = new app();
});

HTML页面

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <div id="contactapp">
        <header>
            <h1>
                通讯录</h1>
        </header>
        <section id="main">
            <ul id="contact-list">
            </ul>
        </section>
        <div class="create">
            <label>
                姓名:<input type="text" id="name" /></label>
            <label>
                电话:<input type="text" id="phone" /></label>
            <input type="button" value="保存" id="add" />
        </div>
    </div>
</body>
<script src="js/require.js" data-main="main" type="text/javascript"></script>
</html>

于是,我们功能完成了:

结语

我和我的小伙伴说,尼玛终于搞完了。。。。。。

posted on 2013-07-29 18:08  叶小钗  阅读(10780)  评论(9编辑  收藏  举报