`

JavaScriptMVC之实战

阅读更多

JavaScriptMVC之实战

下面我们通过一个真实的项目例子来实战JavaScriptMVC。
项目名称:人事系统
开发模块:部门管理
开发工具:Eclipse
技术支持:JavaScriptMVC3.2.2

首先,我们需要到www.javascriptmvc.com下载JavaScriptMVC包,然后解压到目录E:\jQuery\javascriptmvc-3.2.2
下,接着我们点击"开始->运行",输入cmd进入Doc窗口,然后在Doc窗口中cd E:\jQuery\javascriptmvc-3.2.2跳转
到该目录下。

下面我们通过JavaScriptMVC提供的命令生成项目工程:personnel

在Doc窗口输入:js jquery/generate/app personnel 命令生成工程。

整个Doc操作过程如下:

C:\Documents and Settings\lyndon.LINYAOLIANG>E:

E:\>cd E:\jQuery\javascriptmvc-3.2.2

E:\jQuery\javascriptmvc-3.2.2>js jquery/generate/app personnel
      personnel/personnel.css
      personnel/personnel.html
      personnel/personnel.js
      personnel/personnel.md
      personnel/fixtures/fixtures.js
      personnel/funcunit.html
      personnel/models/models.js
      personnel/qunit.html
      personnel/scripts/build.html
      personnel/scripts/build.js
      personnel/scripts/clean.js
      personnel/scripts/crawl.js
      personnel/scripts/docs.js
      personnel/test/funcunit/personnel_test.js
      personnel/test/funcunit/funcunit.js
      personnel/test/qunit/personnel_test.js
      personnel/test/qunit/qunit.js

E:\jQuery\javascriptmvc-3.2.2>

然后在E:\jQuery\javascriptmvc-3.2.2目录下,我们看到一个文件夹personnel,这就是我们的工程。

接着我们需要创建我们需要开发的模块:office 部门管理
接着执行Doc命令:js jquery/generate/scaffold Personnel.Models.Office
生成Office模块的页面。

部门管理模块中部门模块只有2个字段:officeId(不能为空),officeName(可以为空)。

我们首先来完成页面的工作,这部分最提供结果,不提供操作过程,请直接查看工程。

接着我们需要来完成创建,修改部门时检验,在这个校验功能中,我们使用了不少的
插件:
1、jquery/model/validations 校验插件,直接引用这个插件即可。
2、jquery/tie 数据绑定插件
修改这个插件源代码,让这个插件在数据出错时,及时反映出错误。
修改点:

    blur : function(el, ev, val){
        ev.preventDefault();
        if(!this.type && val === undefined){
            val = this.element.val();
        }
        this.inst.attr(this.attr, val, this.proxy('setPrev'), this.proxy('setBack'));
    },
//    change : function(el, ev, val){
//        console.info('change');
//        ev.preventDefault();
//        if(!this.type && val === undefined){
//            val = this.element.val();
//        }
//       
//        this.inst.attr(this.attr, val, this.proxy('setPrev'), this.proxy('setBack'));       
//    },
    setPrev : function(){
        this.element.removeClass("error");
        this.element.attr("title","");       
    },
    setBack : function(errors){
        this.element.addClass("error");
        this.element.attr("title",errors[this.attr][0]);
//        this.setVal(this.lastValue);
    },
 



3、jquery/model 模型
修改这个源代码,让模型在绑定到Form元素上,模型的字段自动绑定到对应的Form下的
input,texterea,select元素上,以名称为准。

当然,我们也可以不修改这个模型,直接在Form下的子元素上加上:
<%= $(el) -> $(el).tie(model,'officeName')%>这句也是同样的效果。
修改源代码,只是为了如果有很多字段的时候,我们一句语句就可以搞定一个Form了。
这个效果是利用了EJS视图的hookup功能,hookup即在视图加载时,如果碰到有对象
存在hookup方法,则会执行这个脚本,这个为我们需要对元素做一些特殊处理很方便,
当然,我们也可以通过View中的helper也可以实现在视图加载时执行helper方法。

修改点:

  hookup: function( el ) {
            var me = this;
            var shortName = this.constructor._shortName,
                models = $.data(el, "models") || $.data(el, "models", {});
            if(el.nodeName == 'FORM'){
                $(el).find("input[name], textarea[name], select[name]").each(function(){
                    $(this).tie(me,$(this).attr("name"));
                });
            }
            $(el).addClass(shortName + " " + this.identity());
            models[shortName] = this;
        }
 

完成校验的最终代码如下:


 

steal('jquery/model', function(){

/**
 * @class Personnel.Models.Office
 * @parent index
 * @inherits jQuery.Model
 * Wraps backend office services.  
 */
$.Model('Personnel.Models.Office',
/* @Static */
{

	init : function(){
		//officeId不能为空,且它只允许输入[0-9a-zA-z]字符
		this.validatePresenceOf('officeId',{message:'部门编号不能为空。'});
		this.validateFormatOf('officeId',/[0-9a-zA-z]/,
		{message:'部门编号只能包含[0-9a-zA-z]字符。'});
	},
	attributes : {
		officeId : 'string'
  	},
	
	/**
	*
	* id:指定对象模型的Id,即在真实中我们使用对象的唯一Id,
	* 这个起什么作用呢?
	* 
	* 在Model中,我们发现无论是修改或者是新建,都是使用save方法,
	* 但是Model是如何知道,我们执行create还是update呢?这个判断就是
	* 靠这个Id了,如果Id存在则说明是修改,没有Id则是新建,Model默认的
	* Id:'id',我们可以像下面一样指定Id
	* 由于这个示例是使用Fixture来执行Ajax,指定Id会影响一些操作,
	* 所以在这里我们没有修改Id,但是,在真实项目中,我们必须指定Id。
	*/
	//id:'officeId',
	findAll: function(params,success,error){
		return $.ajax({
			url: "/offices.json",
			data:params,
			fixture:'-offices',
			success:success,
			error:error,
			dataType:'json'
		});
	},
  	findOne : "/offices/{id}.json", 
  	create : "/offices.json",
 	update : "/offices/{id}.json",
  	destroy : "/offices/{id}.json"
},
/* @Prototype */
{});

})
 




下面我们来实现分页的功能,在这里我们实现分页的效果是,本地分页与远程分页结合。

本地分页插件和分页组件都参考别的实现而完成的,分页是如何实现的,请查看源代码。

完成分页的控制器代码如下:

steal( 'jquery/controller',
       'jquery/view/ejs',
       'jquery/controller/view',
       'personnel/models' )
.then( './views/init.ejs',
       './views/office.ejs',
       './views/detail.ejs',
       './views/editor.ejs',
       function($){

/**
 * @class Personnel.Office.List
 * @parent index
 * @inherits jQuery.Controller
 * Lists offices and lets you destroy them.
 */
$.Controller('Personnel.Office.List',
/** @Static */
{
    defaults : {}
},
/** @Prototype */
{
    init : function(){
        this.element.html(this.view('init') );
        var paging = new PagingMemory({controller:this,model:Personnel.Models.Office,tableId:'officelist'});
        paging.list(10,1,5);
    },
   
    '#officelist a.detail click': function( el ){
        this.element.html(this.view('detail',el.closest('.office').model()));
    },
    '#officelist a.destroy click': function( el ){
        this.element.html(this.view('detail',el.closest('.office').model()));
    },
    '#officelist a.update click': function( el ){
        this.model = el.closest('.office').model();
        this.model.backup();
        this.element.html(this.view('editor',this.model));
    },
    'p.deleteoffice button click':function(el,ev){
        switch(el.attr("name")){
            case 'delete':
            el.closest('div').model().destroy();
            break;
            case 'cancel':
            this.init();
            break;
        }
        return false;
    },
    /**
    * 部门信息修改点击动作处理函数
    */
    'p.updateoffice button click':function(el,ev){
        ev.preventDefault();
        switch(el.attr("name")){
            case 'submit':
            if(this.model.isDirty()){       
                var errors = this.model.errors();
                if(null == errors){   
                    this.model.save();
                }else{
                    for(var error in errors){
                            $("#"+error).addClass("error");
                            $("#"+error).attr("title",errors[error][0]);
                            $("#"+error).focus();
                            return;
                    }
                }               
            }else{
                this.init();
            }
            break;
            case 'reset':
            this.model.restore();
            this.model.backup();
            break;
        }
        return false;
    },
    "{Personnel.Models.Office} destroyed" : function(Office, ev, office) {
        office.elements(this.element).remove();
        this.init();
    },
    "{Personnel.Models.Office} created" : function(Office, ev, office){
        this.init();
    },
    "{Personnel.Models.Office} updated" : function(Office, ev, office){
        this.model.backup();
        this.init();
    }
   
   
});

});
 





最后,我们来实现一下history的功能,即我们在浏览上点击前进/后退的功能,
在这里我们需要使用到插件:jquery/dom/route
因此,我们使用命令创建了模块router,
在Doc窗口执行:js query/generate/scaffold Personnel.Models.Router。

在router模块中,我们添加了一个友好的提示,就是在当我们在修改部门信息时,
信息如果已经被修改,如果我们没有保存,则当我们跳转页面时,会弹出一个
友好提示:当前数据已经修改,是否需要保存?,点击确认则保存,并且跳转。

修改router模块的create.js文件,结果如下:

steal( 'jquery/controller',
       'jquery/view/ejs',
       'jquery/dom/form_params',
       'jquery/controller/view')
    .then('./views/init.ejs', function($){

/**
 * @class Personnel.Router.Create
 * @parent index
 * @inherits jQuery.Controller
 * Creates routers
 */
$.Controller('Personnel.Router.Create',
/** @Prototype */
{
       '{$.route} change' : function(el, ev, attr, how, newVal, oldVal) {
            switch (attr) {
                case 'type':
                    this.nav_change(newVal,oldVal);
                    break;
            }
        },
        nav_change : function(val,oldVal) {
            var controller = $("#content").controller();
            if(controller){
                    if(controller.model){
                        if(controller.model.isDirty()){
                            var btn = confirm("当前数据已经修改,是否需要保存?");
                            if(btn){
                                controller.model.save();
                            }
                        }
                    }
                /**
                * 因为我们都在content的Div上显示视图,
                * 所以在绑定一个控制器之前一定要把之前
                * 的控制器销毁。
                */
                controller.destroy();
            }
            switch(val){
                case 'departmentlist':
                $('#content').personnel_office_list();
                break;
                case 'adddepartment':
                $('#content').personnel_office_create();
                break;
            }
        }
})

});
 




至此我们这个实战完成,现在我们总结一下,我们给大家讲了些什么关键点:

1、如何创建工程,模块。
2、如果校验
3、如何分页
4、如果实现记录点击记录,实现前进和后退。
5、页面如何更友好。

在工程各个文件中,各个文件,我都添加了一些关键的说明,大家要阅读代码,可以看到
这些点都是很有用的。

下面附带上工程源代码。

1
0
分享到:
评论
14 楼 lyndon.lin 2012-06-13  
目前在网上没有这方面的资源,直接到官方网(www.javascriptmvc.com)去看吧,或者浏览我的博客。
13 楼 maizi5401 2012-06-13  
lyndon.lin 写道
这个工程是没有数据表的,是使用JavaScriptMVC的模拟后台fixture,不是真正的后台。虽然所有的操作都没有问题,但是,实际应用上,我们需要把Model中的请求变成我们真正的后台请求。你还没有了解JavaScriptMVC,你先去了解了解再看这个,要不你看不懂的。

谢谢.有啥资料可推荐看得?
12 楼 lyndon.lin 2012-06-12  
这个工程是没有数据表的,是使用JavaScriptMVC的模拟后台fixture,不是真正的后台。虽然所有的操作都没有问题,但是,实际应用上,我们需要把Model中的请求变成我们真正的后台请求。你还没有了解JavaScriptMVC,你先去了解了解再看这个,要不你看不懂的。
11 楼 maizi5401 2012-06-12  
lyndon.lin 写道
还需要修改jquery/tie/tie.js,jquery/model/model.js这2个文件,你看看上面我说的,
校验需要完成那些代码,只要你把上面提供的修改点,更新这2个文件就可以校验了。

那添加功能实现了嘛?
saved : function(el){
$(this.element[0]).children("form")[0].reset();
return false;
}
这段并没有把数据添加到表中,这里怎么取到用户填写的值啊? 谢谢啦
10 楼 lyndon.lin 2012-06-12  
还需要修改jquery/tie/tie.js,jquery/model/model.js这2个文件,你看看上面我说的,
校验需要完成那些代码,只要你把上面提供的修改点,更新这2个文件就可以校验了。
9 楼 maizi5401 2012-06-12  
这个例子中添加部门的function不work, validation有问题
8 楼 maizi5401 2012-06-11  
lyndon.lin 写道
目录结束不对,应该如下:
ROOT\
    documentjs\
    jquery\
    funcunit\
    steal\
    personnel\
      personnel.js
      personnel.html


OK, 好了,我再仔细研究下Code. 谢谢了
7 楼 lyndon.lin 2012-06-11  
目录结束不对,应该如下:
ROOT\
    documentjs\
    jquery\
    funcunit\
    steal\
    personnel\
      personnel.js
      personnel.html
6 楼 maizi5401 2012-06-11  
请问下,这个这么运行? 是放到Tomcat下嘛?
lyndon.lin 写道
放到javascriptmvc根目录下,然后打开personnel.html。

我打开后,点击里面的链接都是失败的,为什么?
5 楼 lyndon.lin 2012-06-11  
放到javascriptmvc根目录下,然后打开personnel.html。
4 楼 maizi5401 2012-06-11  
请问下,这个这么运行? 是放到Tomcat下嘛?
3 楼 步青龙 2012-06-10  
javascript几乎是互联网的半壁江山,发展如此快啊
2 楼 lyndon.lin 2012-06-10  
现在还不广,不过已经有些项目使用了。
1 楼 步青龙 2012-06-10  
好东西啊,这个应用广不广啊?

相关推荐

Global site tag (gtag.js) - Google Analytics