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,閉幕.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM