一场雨

backbone部分代码笔记

backbone:还未发光,就快成了历史选项…

backbone的中文api文档: http://www.css88.com/doc/ backbone/

另一个不错的入门介绍: http://www.ibm.com/developerworks/cn/web/wa-backbonejs/

backbone是第一代前端mvc,很适合来做spa的页面应用。

以及一篇很久之前的博文:JavaScript宝座:七大框架论剑

总的来说,backbone可以写出很优雅的代码,至少是在代码的结构上。

以下我会就之前的一个项目的经历,对backbone的前端流程进行一个介绍,同时也是我自己的一个总结。

1. Backbone与require的结合,进行的模块的异步加载

在加载的index的页面中进行配置:
写在script的第一个,之后就是require的初始化的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
require.config({
baseUrl: 'scripts',
paths: { "jquery": "jquery.min",
"underscore": "underscore.min",
"backbone": "backbone.min" },//名称,路径
shim:{ },//加载没有按照amd规范来写的库或包
urlArgs: "version=1.0.0",
callback: function() {
require(['Application'], function(app) {
app.Start();
});
}
})

最后一个回调的函数,’Application’是依赖的模块,在之前的paths中是有所加载的,然后就是调用’Application’中的一个Start();方法。
阮一峰老师的javascript模块化编程者篇博文就是一篇很不错的文章,另外还可以关注一下AMD规范.

2. Application模块的介绍

Application模块在项目中是一个很基础的模块,但不是toolbox这一类的模块,在这个模块中做了什么,做的是项目初始化的配置和显示,包括登录信息的验证,页面各个主体模块的初始化加载(这些都是在登录验证通过之后进行加载的),就是通过一个start();方法进行的。Start();方法会调用在本模块中的各种方法,同时,本模块中也可以调用其他模块的方法,主要就是通过require来加载的,用的是amd规范。

1
2
3
4
5
define(['toolbox','text!templates/AppTemplate.jst'], function(ToolBox,AppTemplate) {
var Application = {};
return Application;
});

注意的是.jst文件,是视图模板文件,简单的来说就是,用来承接.js文件中的数据,和接受.js文件中逻辑控制显示的模板文件。模板+数据+控制,最后就是页面了,就是单页富集应用。

3. 具体模块中的mvc结构

这边以会员模块为例,路由的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var MemberRouter=Backbone.Router.extend({
initialize:function(){
},
routes:{
"modules/MemberModule":"memberModule",
},
memberModule:function(){//这边是事件的注册
memberEvents.trigger("MemberModule-Entry");//触发事件
Backbone.Events.trigger("to-sub-module",{"name":"会员管理",
"url":"#modules/MemberModule"},2);
//这边做的是面包屑的路由
},
});

视图部分:view

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
var MemberModule = Backbone.View.extend({
template: _.template(MemberTemplate),
initialize: function(){
this.addView=new AddMemberView();
this.memberManager=new MemberManagerView();
this.sendMessageView=new SendMessageView();
this.careForMemberView=new CareForMemberView();
this.careForMemberRecordView=new CareForMemberRecordView();
this.memberBirthdayRecordView=new MemberBirthdayRecordView();
this.memberCardAboutToReachDateRecordView =
new MemberCardAboutToReachDateRecordView();
this.memberHasBeenStoppedCardRecordView =
new MemberHasBeenStoppedCardRecordView();
this.router=new MemberRouter();
memberEvents.on("MemberModule-Entry",this.render,this);
memberEvents.on("MemberModule-cardInstance-info",
this.openCardInstanceInfoPlugin,this);
},
render: function(){
this.$el.html(this.template({"tempId":"member-module"}));
this.$('.list-group>a').hover(function(){
$(this).addClass("active");
},function(){
$(this).removeClass("active");
});
$("#breadCrumbs").show();
return this;
},
openCardInstanceInfoPlugin: function(cardInstanceId){
App.openPluginShow({
"title":"查看会员会籍信息",
"link":"modules/MemberShipModule/plugin/cardInstanceInfo/"
+cardInstanceId,
"originLink":"modules/MemberModule/list",
"context":memberEvents,
"event":"none"
});
},
open: function(baseEL,option){
this.setElement(baseEL);
this.addView.setElement(this.$el);
this.memberManager.setElement(baseEL);
this.sendMessageView.setElement(baseEL);
this.careForMemberView.setElement(baseEL);
this.careForMemberRecordView.setElement(baseEL);
this.memberBirthdayRecordView.setElement(baseEL);//
this.memberCardAboutToReachDateRecordView.setElement(baseEL);//
this.memberHasBeenStoppedCardRecordView.setElement(baseEL);//
}
});

其中包括了对其他的view的引用。在事件的处理上,有对之前的注册的事件的监听,同时还有相应的function进行控制。
‘this.$el.html(this.template({“tempId”:”member-module”}));’ 这边就是 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<h3 style="line-height:34px;">
<span class="glyphicon glyphicon-list"></span>&nbsp;&nbsp;会员管理选项
<a href="" target="_blank" style="float:right;">
<span style="font-size:20px;font-family:'微软雅黑'">查看帮助</span></a>
</h3>
<hr/>
<div class="module-menu">
<div class="list-group">
<a href="#modules/MemberModule/add" class="list-group-item">
<h4 class="list-group-item-heading">新增会员</h4>
<p class="list-group-item-text">创建新会员</p>
</a>
</div>
</div>

以上是一个二级导航页。

在view里面还可以进行操作事件的声明,

1
2
3
4
5
events:{
"click #customernameBtn":"customernamebtn",
},
Customernamebtn:function(){
},

4. 和后台的通信

Fetch();方法从后台获取数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
formParam.fetch({url:"employee/form"}).then(function(data){});
infoCustomer:function(id){
var that=this;
this.model = new CustomerModel({id:id});
this.model.fetch().then(function(res){
# if(res.success){
# that.$el.html(
# that.template({"tempId":"customer-info",
# "data":that.model.toJSON()}
# ));
# }else{
# alert("详情加载失败");
# }
});
},

save() 函数将在后台委托给 Backbone.sync,这是负责发出 RESTful 请求的组件,默认使用 jQuery 函数 $.ajax()。以model为例:

1
2
3
4
5
6
7
8
9
10
11
12
var CustomerModel= ToolBox.BaseModel.extend({
urlRoot:"customer"
});
addCustomer: function(){
var params = ToolBox.formJSON(this.$("#addCustomer"));
var addModel=new CustomerModel();
# addModel.save(params).then(function(res){
# if(res.success){
# alert("保存成功");
# }
# });
}

这边有两个路径的问题:1,后台的url就是“customer”,前台的数据就是通过form表单来获取的,不然通过前台的model创建拼接也是可以的。

5. collection在backbone是一个很基础的模型

在做列表显示的时候,collection有很好的表现。

6. 跨模块直接的调用跳转:

1
2
3
App.mainWrapper.openModule("MemberShipModule",{
redirect:"modules/MemberShipModule/cardInstance/manage"
});

在application中:

1
Application.router.navigate("/",{trigger: true});

所以这边就是1个问题:

1
navigaterouter.navigate(fragment, [options])

其余的还有一些plugin的调用,这边调用的时候用的是.html级的,就存在一些数据的传递的问题,暂不展开。
总之,第一代mvc可以在单个模块之间,多模块之间进行灵活的操作,代码量会很大,但是,横向和纵向来说都可以是代码的结构显得很优雅。
以上。CanvasChen.