QQ技术群:5678537,70210212,77813547 个人网站:http://www.lovewebgames.com 邮箱:55342775@qq.com

javascript的MVC三层架构(案例之分页插件)

javascript的MVC三层架构(案例之分页插件)

作者:田想兵 博客地址:http://www.cnblogs.com/tianxiangbing

最近很少写博文,一是比较忙,二是没啥心情,好,言归正传,今天的主题是MVC版的javascript结构,做程序的,可能对MVC会有较深刻的印象,就是Model-View-Control,中文的意思就是模型-视图-控制器,这好像已经是一个很成熟的结构了,后来又有些在它基础上的拓展,有兴趣的可以摆渡一下。所以它基本上适应任何情况下的编程,今天我们就要用它来实现js版的一个分页控件。

首先,我们先明确每一层是做什么的:

View也就是视图层,在这里面我们会去初始化一些html元素;

Model模型层,我一直认为这一层存在的意义不大,因为通常我们new一个js对象的时候,都会初始化它的一些变量,很少会去单独写个方法去设置它,所以就把Model改成发送ajax请求了;

Control控制器,这里就是一些业务逻辑了,这里我们可以再分出一个事件层来;

Event事件层,处理html事件。

中途停了一天,接着写,不知道为啥,最近一直都没有办法集中精力,可能是因为儿童节吧,今天还要加班, 可悲的码农啊,题外话不说了,继续码字。

现在我们来分析下需求,分页控件,无非就是对数据的一个分组显示,所以它一定会有pagesize(每页条数)和count(总条数) 这两个属性,当然也有人喜欢把所有数据返回过来给前端来分页,不过分页的目的之一,就是为了减轻数据量,一次批量返回也不是不行,具体情况具体分析吧!有了count和pagesize后,我们就可以算出总页码数了。

parseInt( count % pageSize >0 ?count / pageSize+1:count/pagesize)

这个很简单,就是整除有余的话就多一页,否则取整数部分。

我们先看下效果图,不然的话,脑子里没有一个结构,也是无法下手的。请观看下图:

 

 

 

接着该MVC三层结构出场了,我们先在view(视图层)初始化一些必要的HTML元素:

view:function(method,args){        
        var _self=this;    
        var _class={
            page:function(args){
                var _html='\
                        <div class="pager">\
                            <a class="firstPage" href="javascript:void(0);">首页</a>\
                            <a class="prePage" href="javascript:void(0);">上一页</a>\
                            <span class="inputPage">第<input type="text" value="'+ _self.currentIndex +'" class="txt_curIndex" name="txt_curIndex"/>页/<i>'+_self.sumPage+'</i>页</span>\
                            <a class="nextPage" href="javascript:void(0);">下一页</a>\
                            <a class="lastPage" href="javascript:void(0);">末页</a>\
                        </div>\
                            ';
                _self.content.html(_html);
                _self.event("bind",args);
            }
        };
        return _class[method](args);
    }

 在这里,我又调用了事件层,来给这些HTML元素绑定相应的事件,这里大概有五个事件,就是上一页,下一页,首页,未页,及跳转。这些事件,其本质就是改变页码数,好,那我们就写个请求页码数的方法:

model:function(method,args){
        var _self=this;
        var _class={
            go:function(args){
                return $.ajax({
                    url:_self.ajaxUrl,
                    dataType:"json",
                    async:true,
                    data:args[0],
                    success:function(data){
                        args[1](data);
                        _self.cpu("change",data);
                    },
                    type:"GET",
                    error:function(data){
                         alert("json格式不正确")
                    }
                });
            }
        };
        return _class[method](args);
    }

这是个ajax请求,放在model层下面,有两个参数,一个是ajax需要传的参数{page:1} args[0],另一个是外部的一个回调方法,用来格式化内容的,这个跟分页控件没有半毛钱关系,所以就当作回调。好,接着我们在控制器层里就调用这个方法就行了,刚才说到有五个事件,这样就对应了五个控制器:

View Code
    cpu:function(method,args){
        var _self=this;
        var _class={
            change:function(data){
                var arr = data;
                if (data.count>0){
                    _self.count=data.count;
                    _self.sumPage= parseInt( _self.count % _self.pageSize >0 ? _self.count / _self.pageSize+1 : _self.count / _self.pageSize);
                    _self.view("page");
                }
            },                
            jump:function(args){
                var input = parseInt($("[name='txt_curIndex']",_self.content).val());
                if (input>0 && input <= _self.sumPage){
                    _self.currentIndex = input;
                    _self.ajaxArgs.page = _self.currentIndex-1;
                    _self.model("go",[_self.ajaxArgs,_self.returnFunc]);
                }
            },
            prev:function(args){
                if (_self.currentIndex > 1){
                    _self.currentIndex--;
                    $("[name='txt_curIndex']",_self.content).val(_self.currentIndex);
                    _self.cpu("jump",args);
                }
            },
            next:function(args){                
                if (_self.currentIndex < _self.sumPage - 1){
                    _self.currentIndex++;
                    $("[name='txt_curIndex']",_self.content).val(_self.currentIndex);
                    _self.cpu("jump",args);
                }
            },
            last:function(args){
                _self.currentIndex = _self.sumPage;
                $("[name='txt_curIndex']",_self.content).val(_self.currentIndex);
                _self.cpu("jump",args);
            },
            first:function(args){
                _self.currentIndex = 1;
                $("[name='txt_curIndex']",_self.content).val(_self.currentIndex);
                _self.cpu("jump",args);
            }
        };
        return _class[method](args);
    }
};

 数一数,是不是五个,我勒个去,作者数学不好,竟然是他妹的六个,竟然多了个change,好啦,把chage这个放model里去吧,他的作用就是计算一些变量的值。

最后事件层只需要调用Control控制层相对应的方法就行了:

    event:function(method,args){
        var _self=this;
        var pager = $("div.pager",_self.content);
        var _class={
            bind:function(args){
                $("[name='txt_curIndex']",_self.content).keydown(function(e){
                    if (e.keyCode==13){
                        _self.cpu("jump",args);
                    }
                });
                $(".prePage",_self.content).click(function(){
                    _self.cpu("prev",args);
                });    
                $(".nextPage",_self.content).click(function(){
                    _self.cpu("next",args);
                });
                $(".lastPage",_self.content).click(function(){
                    _self.cpu("last",args);
                });
                $(".firstPage",_self.content).click(function(){
                    _self.cpu("first",args);
                });
            }
        };
        return _class[method](args);
    },

这样是不是就完了呢,你猜?没错,恭喜你,猜对了,还没有结束,因为我们还没有看到入口,一般情况我们都喜欢定义一个名为init的方法来初始化,这次的情况也很一般,所以定义init吧:

init:function(ops){
        var _self = this;
        _self.currentIndex = ops.currentIndex;
        _self.ajaxArgs = $.extend( ops.ajaxArgs,{page:this.currentIndex-1});
        _self.model("go",[_self.ajaxArgs,_self.returnFunc]);
    },

整个分页插件的代码如下:

View Code
function Pager(ops){
    this.currentIndex = 1;
    this.count = ops.count;
    this.pageSize = ops.pageSize||10;
    this.sumPage = 1;
    this.content = ops.content;
    this.ajaxUrl = ops.url;
    this.returnFunc=ops.returnFunc||new Function();
};
Pager.prototype={
    init:function(ops){
        var _self = this;
        _self.currentIndex = ops.currentIndex;
        _self.ajaxArgs = $.extend( ops.ajaxArgs,{page:this.currentIndex-1});
        _self.model("go",[_self.ajaxArgs,_self.returnFunc]);
    },
    view:function(method,args){        
        var _self=this;    
        var _class={
            page:function(args){
                var _html='\
                        <div class="pager">\
                            <a class="firstPage" href="javascript:void(0);">首页</a>\
                            <a class="prePage" href="javascript:void(0);">上一页</a>\
                            <span class="inputPage">第<input type="text" value="'+ _self.currentIndex +'" class="txt_curIndex" name="txt_curIndex"/>页/<i>'+_self.sumPage+'</i>页</span>\
                            <a class="nextPage" href="javascript:void(0);">下一页</a>\
                            <a class="lastPage" href="javascript:void(0);">末页</a>\
                        </div>\
                            ';
                _self.content.html(_html);
                _self.event("bind",args);
            }
        };
        return _class[method](args);
    },
    event:function(method,args){
        var _self=this;
        var pager = $("div.pager",_self.content);
        var _class={
            bind:function(args){
                $("[name='txt_curIndex']",_self.content).keydown(function(e){
                    if (e.keyCode==13){
                        _self.cpu("jump",args);
                    }
                });
                $(".prePage",_self.content).click(function(){
                    _self.cpu("prev",args);
                });    
                $(".nextPage",_self.content).click(function(){
                    _self.cpu("next",args);
                });
                $(".lastPage",_self.content).click(function(){
                    _self.cpu("last",args);
                });
                $(".firstPage",_self.content).click(function(){
                    _self.cpu("first",args);
                });
            }
        };
        return _class[method](args);
    },
    model:function(method,args){
        var _self=this;
        var _class={
            go:function(args){
                return $.ajax({
                    url:_self.ajaxUrl,
                    dataType:"json",
                    async:true,
                    data:args[0],
                    success:function(data){
                        args[1](data);
                        _self.model("change",data);
                    },
                    type:"GET",
                    error:function(data){
                    console.dir(data)
                         alert("json格式不正确")
                    }
                });
            },
            change:function(data){
                var arr = data;
                if (data.count>0){
                    _self.count=data.count;
                    _self.sumPage= parseInt( _self.count % _self.pageSize >0 ? _self.count / _self.pageSize+1 : _self.count / _self.pageSize);
                    _self.view("page");
                }
            }
        };
        return _class[method](args);
    },
    cpu:function(method,args){
        var _self=this;
        var _class={                
            jump:function(args){
                var input = parseInt($("[name='txt_curIndex']",_self.content).val());
                if (input>0 && input <= _self.sumPage){
                    _self.currentIndex = input;
                    _self.ajaxArgs.page = _self.currentIndex-1;
                    _self.model("go",[_self.ajaxArgs,_self.returnFunc]);
                }
            },
            prev:function(args){
                if (_self.currentIndex > 1){
                    _self.currentIndex--;
                    $("[name='txt_curIndex']",_self.content).val(_self.currentIndex);
                    _self.cpu("jump",args);
                }
            },
            next:function(args){                
                if (_self.currentIndex < _self.sumPage - 1){
                    _self.currentIndex++;
                    $("[name='txt_curIndex']",_self.content).val(_self.currentIndex);
                    _self.cpu("jump",args);
                }
            },
            last:function(args){
                _self.currentIndex = _self.sumPage;
                $("[name='txt_curIndex']",_self.content).val(_self.currentIndex);
                _self.cpu("jump",args);
            },
            first:function(args){
                _self.currentIndex = 1;
                $("[name='txt_curIndex']",_self.content).val(_self.currentIndex);
                _self.cpu("jump",args);
            }
        };
        return _class[method](args);
    }
};

OK,最后我们回过头来看下,这个结构的优劣点,优点了,就是更方便于扩展,可以无限制的往下加,层次分得较清明,劣点是,层次过深,效率会低一些,而且看着不爽,所以我给他定位为,管理系统业务逻辑较多时使用,一般的JS效果插件还是使用扁平结构的好。今天就写到这吧,谢谢您的观看,最后的台词是:如果你有任何的疑问都不要来问我,请反复阅读本文。也可以加入我的QQ群与其他人讨论,本文的DEMO会放在群共享里。我的群号有5678537,70210212,闭幕.

posted @ 2012-06-02 12:25 田想兵 阅读(...) 评论(...) 编辑 收藏
联系QQ:55342775,QQ技术群:5678537,70210212,77813547 个人网站:http://www.lovewebgames.com 邮箱:55342775@qq.com