此方案是一次将MVC的思想引入客户端的尝试. 结合AJAX , 并借鉴了一些ASP.NET MVC的实现模式.

 

示例是一个简单的事件管理系统, 只有一个页面, 用户可以提交事件(post), 回复(reply). 页面打开时列表方式展现事件及回复.

 

Controller公开一系列action 给调用方.


action主要做三类事:

1. 使用ajax方式与服务器端通信(ajax)

2. 维护viewModel实例的状态

3. 刷新页面的局部视图

 

 

Controller
1 /* construct */
2  function Controller(){
3 this.viewModel = new ViewModel();
4 }
5
6  /* public methods */
7 Controller.prototype.index = function(){
8 var controller = this;
9 controller._bindEventList();
10 };
11 Controller.prototype.post = function(title, content, callback){
12 var controller = this;
13 $.ajax('/event/post', {
14 title: title,
15 content: content
16 },
17 function(newEvent){
18 if (controller.viewModel.pageIndex == 1){
19 // may be there are (pageSize + 1) items.
20   controller.viewModel.eventList.push(newEvent);
21 } else{
22 controller.viewModel.pageSize = 1;
23 controller._bindEventList();
24 }
25 callback && callback();
26 });
27 };
28 Controller.prototype.reply = function(eventId, content, callback){
29 var controller = this;
30 // todo: 'find' need create
31   controller.viewModel.selectedEvent = controller.viewModel.eventList.find(eventId);
32 $.ajax('/event/reply', {
33 eventId: controller.viewModel.selectedEvent.Id,
34 content: content
35 },
36 function(newReply){
37 controller.viewModel.selectedEvent.ReplyList.push(newReply);
38 // still show(refresh) the page where the selected event in.
39   controller._bindEventList();
40 callback && callback();
41 });
42 };
43
44  /* public events */
45  // refactory: use better solution replaces 'null'
46  Controller.prototype.afterEventListBinded = null;
47
48  /* private methods */
49 Controller.prototype._bindEventList = function(callback){
50 $.ajax('/event/list', {
51 pageSize: controller.viewModel.pageSize
52 },
53 function(result){
54 controller.viewModel.eventList = result.eventList;
55 controller.viewModel.pageCount = result.pageCount;
56 // renderTemplate is a custom wrapper of jTemplates
57   renderTemplate('event-list', {
58 eventList: controller.viewModel.eventList,
59 pageIndex: controller.viewModel.pageIndex,
60 pageSize: controller.viewModel.pageSize,
61 pageCount: controller.viewModel.pageCount
62 });
63
64 controller.afterEventListBinded && controller.afterEventListBinded();
65
66 callback && callback();
67 };
68 };
69  

 

 

 

Controller引用着一个ViewModel的实例, ViewModel的定义如下:

1 /* construct */
2  function ViewModel(){
3 this.eventList = [];
4 this.selectedEvent = null;
5 this.pageIndex = 1;
6 this.pageSize = 10;
7 this.pageCount = 0;
8 }

 

调用示例:

这个示例是jquery版的, DOM中也能看到jTemplates的影子(一个jquery插件), 但从思想到实现, 这个方案并不依赖于jquery, Controller中的两处外部依赖($.ajax和renderTemplate)完全可以寻找其他等价物替代.

此示例项目选用jquery和jTemplates完全是项目选型决定, 实现上只是借用了现成的便利.

 

1 /* page ready */
2 $(function(){
3 var controller = new Controller();
4 // event bind
5   controller.afterEventListBinded = function(){
6 $('.btnReply').click(function(){
7 var eventId = $(this).attr('eventId');
8 var content = $('.txtReply', $(this).parent()).val();
9
10 controller.reply(eventId, content,
11 function(){
12 alert('reply successful');
13 });
14 });
15 };
16
17 controller.index();
18
19 $('#btnPost').click(function(){
20 var title = $('#txtTitle').val();
21 var content = $('#txtContent').val();
22 controller.post(title, content,
23 function(){
24 alert('post successful');
25 });
26 });
27 });

 

 

 

DOM
1 <div>
2 <textarea od="txtContent" ></textarea>
3 <input type="button" id="btnPost" />
4  </div>
5  <div id="event-list">
6 <!-- render template -->
7 <textarea id="event-list-template" class="template">
8 <ul>
9 {#for $T.eventList as event }
10 <li>
11 <div>{$T.event.title} | {$T.event.accountId} | {$T.event.insertDate}</div>
12 <div>{$T.event.content}</div>
13 {#for $T.event.replyList as reply }
14 <div>{$T.reply.accoutId}| {$T.reply.insertDate}</div>
15 <div>{$T.reply.content}</div>
16 {/#for}
17 <textarea class="txtReply" ></textarea>
18 <input type="button" value="reply" class="btnReply" eventId="{$T.event.eventId}" />
19 </li>
20 {/#for}
21 </ul>
22 <div>{$T.pageIndex} in {$T.pageSize}, total: {$T.pageCount}<div>
23 </textarea>
24  </div>

(DOM中 <textarea class="template">... </textarea>是一个 jTemplates 模板)

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架