51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

分享“分页”插件的前端开发过程

500.jpg

在数据显示的时候,我们经常会遇到分页功能,相对于瀑布流功能,分页还是比较传统且实用。在移动端&APP的数据加载,我们更多的采用数据瀑布流的功能来代替分页,比如新浪新闻、网易新闻APP客户端等等。但是在PC端,我们为了追求页面美观,还是要用到分页功能,所以掌握"分页"的功能是前端开发者的基本技能吧。今天我们一起来学习下"分页"插件的前端开发过程。

在开始学习之前,我一起来看下一个DEMO:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>分页功能 - Web前端之家www.jiangweishan.com</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
        <style type="text/css">
            .pagenavigate{
                    border:1 solid #78cdd1;
                    width:20px;
                    height:20px;
                    line-height:20px;
                    text-align:center;
                    background-color:#90d7ec;
                    float:left;
                    margin:0 2px;
            }

            .pagenext,.pagelast,.pagefirst,.pagepre{
                border:1 solid #78cdd1;
                width:40px;
                height:20px;
                line-height:20px;
                text-align:center;
                float:left;
                margin:0 1px;
            }

            .pagenavigate a{
                    width:20px;
                    height:20px;
                    color:#fffef9;
                    background-color:#90d7ec;
                    text-decoration:none;
            }


            .pagenext a,.pagelast a,.pagefirst a,.pagepre a{
                width:40px;
                height:20px;
                color:#009ad6;
                font-size:12px;
                text-decoration:none;
                
            }
            #contents{
                height:150px;    
            }
            .pagenavigateon{
                    border:1 solid #78cdd1;
                    width:20px;
                    height:20px;
                    line-height:20px;
                    text-align:center;
                    color:#ff0000!important;
                    background-color:#90d7ec;
            }

            .pagenavigateon a{
                    color:#ff0000;
                    text-decoration:none;
            }
        </style>
    </head>
        
    <body>
        <div id="contents">
            <div class="contentlist">1.美国宣布新军事战略将重心转向亚太地区</div>
            <div class="contentlist">2.春运期间极端最低温达零下5度</div>
            <div class="contentlist">3.上海妇女社会地位调查结果公布</div>
            <div class="contentlist">4.暖手袋发生漏液有危险 </div>
            <div class="contentlist">5.上海相关调查称新车内挥发性有机物严重超标</div>
            <div class="contentlist">6.申城进入流感高发期</div>
            <div class="contentlist">7.上海仍有部分幼儿园开设各类收费兴趣班 家长支持</div>
            <div class="contentlist">8.达人秀将揭晓复赛阵容 洗碗工麻袋姐走改编路线</div>
            <div class="contentlist">9.苹果侵权中国作家立案 韩寒等9人索赔1200万元</div>
            <div class="contentlist">10.嘉汇广场一商务楼外墙剥落砸伤过路男子(图)</div>
            <div class="contentlist">11.石岚二村小区高空抛物现象严重 多辆轿车被砸</div>
            <div class="contentlist">12.女子从11家银行申领24张信用卡 透支本金45万</div>
            <div class="contentlist">13.松江一家化工厂发生爆炸 一名技术工人当场死亡</div>
            <div class="contentlist">14.UPS公司内鬼组团集体犯罪侵占公司运费980多万元</div>
            <div class="contentlist">15.奔驰车胎漏气监测不报警</div>
            <div class="contentlist">16.CBA-新疆新援能否战JR 连败北京遇强敌</div>
            <div class="contentlist">17.科比30+8湖人负开拓者 詹韦休战热火三加时胜老鹰</div>
            <div class="contentlist">18.英媒惊曝曼联挖角兰帕德 小贝最新内裤广告超酷造型</div>
            <div class="contentlist">19.曼奇尼笑迎孙继海 英主力紧拥</div>
            <div class="contentlist">20.冬运花滑庞清佟健复出夺冠 </div>
            <div class="contentlist">21.中国彩票年销2214亿涨33%</div>
            <div class="contentlist">22.双色球26注530万分落14省市</div>
            <div class="contentlist">23.安全是根本 自主品牌C-NCAP碰撞评说</div>
            <div class="contentlist">24.赏豪车买车尽在车型总汇</div>
            <div class="contentlist">25.蔡澜:风情万种的日本版朱茵</div>
            <div class="contentlist">26.微访谈:黄觉其实是个艺术家</div>
            <div class="contentlist">27.杨澜访邓婕:当家庭主妇难</div>
            <div class="contentlist">28.中学女生迎新“黑丝”上阵</div>
            <div class="contentlist">29.陆空三军都干过的将军</div>
            <div class="contentlist">30.科比无敌1挑2!180度转体颜扣 103中51别再骂他打铁</div>
            <div class="contentlist">31.2米13神塔玩出白巧绝技 湖人新体系?瞎子才忽视他</div>
            <div class="contentlist">32.湖人22+15霸王8天后跌落人间 大梦鲨鱼附体?还早呢 </div>
            <div class="contentlist">33.纳什17助攻太阳大胜雄鹿</div>
            <div class="contentlist">34.单节17分!非同级别较量 阿联渐入状态归队日子临近</div>
            <div class="contentlist">35.状元秀21分骑士负开拓者</div>
            <div class="contentlist">36.38岁纳什1战写65年纪录 10+17!最美就是这不老传奇</div>
            <div class="contentlist">37.开拓者老大遭梦之队冷落 直言想打奥运哪怕选拔赛</div>
            <div class="contentlist">38.雷霆大将右膝十字韧带撕裂 确定赛季报销择日手术</div>
            <div class="contentlist">39.博格特周三回归对阵马刺 经纪人:感谢各方的支持</div>
            <div class="contentlist">40.詹皇转变创造惊艳开局 哈队:谁能在内线防住他?</div>
            <div class="contentlist">41.斯帅新赛季给波什两特权 龙王:当个组织者真难啊</div>
            <div class="contentlist">42.连夜赶场累坏热火将士 詹姆斯:感觉像飞了趟中国</div>
            <div class="contentlist">43.米勒打勇士复出?NO!再观察 斯帅:他还需要训练</div>
            <div class="contentlist">44.热火迎赛季首次完整训练 斯帅惜时如金飞机上放录像</div>
            <div class="contentlist">45.不再为忠诚or冠军挣扎 纳什:我愿在太阳到日落</div>
            <div class="contentlist">46.石佛退居二线马刺愿供养 布莱尔:歇到季后赛再打</div>
            <div class="contentlist">47.前蜂王欲组团买下母队 :我识人懂商会十分完美</div>
            <div class="contentlist">48.魔兽仅5分4板仍克国王 雷霆灭马刺背靠背靠背全胜</div>
            <div class="contentlist">49.赏豪车买车尽在车型总汇</div>
            <div class="contentlist">50.蔡澜:风情万种的日本版朱茵</div>
            <div class="contentlist">51.微访谈:黄觉其实是个艺术家</div>
            <div class="contentlist">52.杨澜访邓婕:当家庭主妇难</div>
            <div class="contentlist">53.中学女生迎新“黑丝”上阵</div>
            <div class="contentlist">54.陆空三军都干过的将军</div>
            <div class="contentlist">55.科比无敌1挑2!180度转体颜扣 103中51别再骂他打铁</div>
            <div class="contentlist">56.2米13神塔玩出白巧绝技 湖人新体系?瞎子才忽视他</div>
            <div class="contentlist">57.湖人22+15霸王8天后跌落人间 大梦鲨鱼附体?还早呢 </div>
            <div class="contentlist">58.纳什17助攻太阳大胜雄鹿</div>
            <div class="contentlist">59.单节17分!非同级别较量 阿联渐入状态归队日子临近</div>
            <div class="contentlist">60.状元秀21分骑士负开拓者</div>
            <div class="contentlist">61.嘉汇广场一商务楼外墙剥落砸伤过路男子(图)</div>
            <div class="contentlist">62.石岚二村小区高空抛物现象严重 多辆轿车被砸</div>
            <div class="contentlist">63.女子从11家银行申领24张信用卡 透支本金45万</div>
            <div class="contentlist">64.松江一家化工厂发生爆炸 一名技术工人当场死亡</div>
            <div class="contentlist">65.UPS公司内鬼组团集体犯罪侵占公司运费980多万元</div>
            <div class="contentlist">66.奔驰车胎漏气监测不报警</div>
            <div class="contentlist">67.CBA-新疆新援能否战JR 连败北京遇强敌</div>
            <div class="contentlist">68.科比30+8湖人负开拓者 詹韦休战热火三加时胜老鹰</div>
            <div class="contentlist">69.英媒惊曝曼联挖角兰帕德 小贝最新内裤广告超酷造型</div>
            <div class="contentlist">70.曼奇尼笑迎孙继海 英主力紧拥</div>
            <div class="contentlist">71.冬运花滑庞清佟健复出夺冠 </div>
            <div class="contentlist">72.中国彩票年销2214亿涨33%</div>
            <div class="contentlist">73.双色球26注530万分落14省市</div>
            <div class="contentlist">74.安全是根本 自主品牌C-NCAP碰撞评说</div>
            <div class="contentlist">75.赏豪车买车尽在车型总汇</div>
            <div class="contentlist">76.蔡澜:风情万种的日本版朱茵</div>
        </div>
        <br/><br/><br/>
        
        <div id="navigatediv">
        
        </div>    
        <script type="text/javascript" src="/demo/js/jq.js">
        </script>
        <script type="text/javascript">
        //插件定义
        ;(
            function($){
                $.extend({
                        "easypage":function(options){
                            options = $.extend({//参数设置
                                contentclass:"contentlist",//要显示的内容的class
                                navigateid:"navigatediv",//导航按钮所在的dom的id
                                everycount:"5",//每页显示多少个
                                navigatecount:"5"//导航按钮一次显示多少个
                                },
                                options);
                            var currentpage = 0;//当前页    
                            var contents = $("."+options.contentclass);//要显示的内容
                            var contentcount = contents.length;//得到内容的个数
                            var pagecount = Math.ceil(contentcount/options.everycount);//计算出页数
                            //拼接导航按钮
                            var navigatehtml = "<div id='pagefirst' class='pagefirst'><a href='javascript:void(0)'>首页</a></div><div id='pagepre' class='pagepre'><a href='javascript:void(0)'>上一页</a></div>";
                            for(var i = 1;i <= pagecount;i++){
                                    navigatehtml+='<div class="pagenavigate"><a href="javascript:void(0)">'+i+'</a></div>';
                            }
                            navigatehtml+="<div id='pagenext' class='pagenext'><a href='javascript:void(0)'>下一页</a></div><div id='pagelast' class='pagelast'><a href='javascript:void(0)'>尾页</a></div>";
                            
                            //加载导航按钮
                            $("#"+options.navigateid).html(navigatehtml);    
                            
                            //得到所有按钮
                            var navigates = $(".pagenavigate");
                            
                            //隐藏所有的导航按钮
                            $.extend({
                                "hidenavigates":function(){
                                    navigates.each(function(){
                                        $(this).hide();
                                    })    
                                }    
                            });
                            
                            //显示导航按钮
                            $.extend({
                                "shownavigate":function(currentnavigate){
                                    $.hidenavigates();
                                    var begin = currentnavigate>=options.navigatecount?currentnavigate-parseInt(options.navigatecount):0;
                                    if(begin>navigates.length-2*options.navigatecount){
                                        begin = navigates.length-2*options.navigatecount;    
                                    }
                                    for(var i = begin;i < currentnavigate+parseInt(options.navigatecount);i++){
                                        $(navigates[i]).show();
                                    }
                                }    
                            });
                            
                            //高亮显示某个按钮
                            $.extend({
                                "lightnavigate":function(currentnavigate){
                                    currentnavigate.addClass("pagenavigateon");    
                                }    
                            });
                            
                            //移除所有高亮按钮
                            $.extend({
                                "removelight":function(){
                                    $(".pagenavigateon").each(
                                        function(){
                                            $(this).removeClass("pagenavigateon");    
                                        }
                                    )
                                 }    
                            });
                            
                            //显示某页的内容
                            $.extend({
                                "showPage":function(page){
                                    contents.each(
                                        function(contentindex){
                                            if(contentindex>=page*options.everycount && contentindex < (page+1)*options.everycount){
                                            $(this).show();    
                                            }else{
                                            $(this).hide();    
                                            }
                                        }
                                    );
                                }
                            });
                            
                            //隐藏前进后退按钮
                            $.extend({
                                "hidePreNext":function(page){
                                        if(page==pagecount-1){
                                            $("#pagenext").hide();    
                                            $("#pagelast").hide();
                                            $("#pagepre").show();
                                            $("#pagefirst").show();            
                                        }else if(page==0){
                                            $("#pagepre").hide();
                                            $("#pagefirst").hide();    
                                            $("#pagenext").show();    
                                            $("#pagelast").show();    
                                        }else{
                                            $("#pagenext").show();
                                            $("#pagepre").show();    
                                            $("#pagefirst").show();    
                                            $("#pagelast").show();    
                                        }
                                }    
                            });
                            //显示指定的导航按钮
                            $.shownavigate(0);
                            //隐藏所有的内容
                            $.showPage(0);
                            //开始时隐藏后退按钮
                            $.hidePreNext(0);
                            //高亮显示第一个按钮
                            if(pagecount>0){
                                    $.lightnavigate($(navigates.get(0)));
                            }
                            //点击导航按钮
                            $(".pagenavigate").each(
                                function(myindex){
                                    $(this).click(
                                        function(){
                                            $.showPage(myindex);
                                            $.removelight();
                                            $.lightnavigate($(this));
                                            currentpage = myindex;
                                            $.hidePreNext(currentpage);
                                            var na = Math.floor((currentpage+1)/options.navigatecount)*options.navigatecount;
                                            $.shownavigate(na);    
                                        }
                                    );
                                }
                            );
                            //点击后退按钮
                            $("#pagepre").click(
                                function(){
                                    --currentpage<=0 && (currentpage=0);
                                    $.showPage(currentpage);    
                                    $.removelight();
                                    $.lightnavigate($(navigates.get(currentpage)));
                                    $.hidePreNext(currentpage);
                                    var na = Math.floor(currentpage/options.navigatecount)*options.navigatecount;
                                    $.shownavigate(na);    
                                }
                            );
                            //点击前进按钮
                            $("#pagenext").click(
                                function(){
                                    ++currentpage>=pagecount-1 && (currentpage=pagecount-1);
                                    $.showPage(currentpage);    
                                    $.removelight();
                                    $.lightnavigate($(navigates.get(currentpage)));
                                    $.hidePreNext(currentpage);
                                    
                                    var na = Math.floor((currentpage+1)/options.navigatecount)*options.navigatecount;
                                    $.shownavigate(na);    
                                }
                            );
                            //点击首页按钮
                            $("#pagefirst").click(
                                function(){
                                    currentpage=0;
                                    $.showPage(currentpage);    
                                    $.removelight();
                                    $.lightnavigate($(navigates.get(currentpage)));
                                    $.hidePreNext(currentpage);
                                    
                                    var na = Math.floor((currentpage+1)/options.navigatecount)*options.navigatecount;
                                    $.shownavigate(na);    
                                }
                            );
                         //点击尾页按钮
                         $("#pagelast").click(
                                 function(){
                                     currentpage=pagecount-1;
                                     $.showPage(currentpage);    
                                    $.removelight();
                                    $.lightnavigate($(navigates.get(currentpage)));
                                    $.hidePreNext(currentpage);
                                    
                                    var na = Math.floor((currentpage+1)/options.navigatecount)*options.navigatecount;
                                    $.shownavigate(na);    
                                 }
                         );
                        }
                });
            }
        )(jQuery)    

        //插件调用开始
            //contentclass   要分页内容的class名称 默认的为contentlist
            //navigateid         放置导航按钮的位置id 默认为mynavigate
            //everycount          每页显示多少个
            //navigatecount     导航按钮开始显示多少个,从第二个开始显示为双倍    
            $(
                function(){
                    $.easypage({'contentclass':'contentlist','navigateid':'navigatediv','everycount':5,'navigatecount':5});    
                }
            )
        </script>    


    </body>    
</html>

由于代码比较多,所以这里我们只能大概的说明下核心知识,更细节的东西需要大家自己去学习。

从上面的效果来看,后台将查询出来的内容全部显示到页面上,这个插件要控制这些内容,使其一页一页显示。有上一页,下一页,首页,尾页的功能。在第一页时,上一页,首页要隐藏。在最后一页时,尾页,下一页要隐藏。一次只显示几个按钮,当点击当次最后一个按钮时,显示后面几个。

接下来简单说一下编码过程:

首先可以大胆的先写下以下的代码:

//为了更好的兼容性,开始前有个分号
;(
function($){//此处将$作为匿名函数的形参
}
)(jQuery)//将jQuery作为实参传递给匿名函数

这段代码大家应该不陌生,就是javascript的神级特性---闭包。这也是jQuery插件的常见结构。为什么要使用闭包来作这jQuery的常用结构呢,一来既可以避免内部临时变量影响全局空间,又可以在插件内部继续使用$作为jQuery的别名。

接下来就是在这个结构里面写自己的方法了,jQuery提供了两种方式可以在jQuery里面扩展方法。打开jQuery API,找到插件机制,可以看到两个方法:

• jQuery.extend(object) 扩展jQuery对象本身。用来在jQuery命名空间上增加新函数。
• jQuery.fn.extend(object) 扩展 jQuery 元素集来提供新的方法(通常用来制作插件)。
从上面可以看到jQuery.extend(object)是扩展jQuery本身,要是参照java或者C#这些语言的角度来讲,就相当于向jQuery中添加静态方法。比如说我们这样写:

jQuery.extend({
     "max":function(){
          return max;
     }
})

这样,就相当于在jQuery对象里面添加了一个max方法,调用的时候可以进行这样调用:jQuery.max()

那么,jQuery.fn是什么呢,打开jQuery源码,可以看到 jQuery.fn = jQuery.prototype。那么jQuery.fn.extend相当于在jQuery中添加成员函数。

这样子应该明白两者之间的区别了吧,静态方法可以直接调用,jQuery.max()。成员函数只有jQuery实例可以调用,比如jQuery("#my").max()。

这里我采用jQuery.extend方法。代码如下:

;(
 function($){
  $.extend({
   "easypage":function(options){
   options = $.extend({//参数设置
   contentclass:"contentlist",//要显示的内容的class
   navigateid:"navigatediv",//导航按钮所在的容器的id
   everycount:"5",//每页显示多少个
   navigatecount:"5"//导航按钮一次显示多少个
   }, options); });

easypage就是使用分页插件使用的方法名,contentclass,navigateid,everycount,navigatecount是参数。

基本框架已经搭好了,接下来就是完成功能。

首先是要找到要分页的内容,并生成导航按钮。代码如下:

var currentpage = 0;//当前页 
var contents = $("."+options.contentclass);//要显示的内容
var contentcount = contents.length;//得到内容的个数
var pagecount = Math.ceil(contentcount/options.everycount);//计算出页数
//拼接导航按钮
var navigatehtml = "<div id='pagefirst' class='pagefirst'><a href='javascript:void(0)'>首页</a></div><div id='pagepre' class='pagepre'><a href='javascript:void(0)'>上一页</a></div>";
for(var i = 1;i <= pagecount;i++){
 navigatehtml+='<div class="pagenavigate"><a href="javascript:void(0)">'+i+'</a></div>';
}
navigatehtml+="<div id='pagenext' class='pagenext'><a href='javascript:void(0)'>下一页</a></div><div id='pagelast' class='pagelast'><a href='javascript:void(0)'>尾页</a></div>";
//加载导航按钮
$("#"+options.navigateid).html(navigatehtml)

这段代码比较简单,有一些JS基础的都可以搞定。

接下来就是就是实现一些基本的功能,这里抽取其中两个显示。

var currentpage = 0;//当前页 
var contents = $("."+options.contentclass);//要显示的内容
var contentcount = contents.length;//得到内容的个数
var pagecount = Math.ceil(contentcount/options.everycount);//计算出页数
//拼接导航按钮
var navigatehtml = "<div id='pagefirst' class='pagefirst'><a href='javascript:void(0)'>首页</a></div><div id='pagepre' class='pagepre'><a href='javascript:void(0)'>上一页</a></div>";
for(var i = 1;i <= pagecount;i++){
 navigatehtml+='<div class="pagenavigate"><a href="javascript:void(0)">'+i+'</a></div>';
}
navigatehtml+="<div id='pagenext' class='pagenext'><a href='javascript:void(0)'>下一页</a></div><div id='pagelast' class='pagelast'><a href='javascript:void(0)'>尾页</a></div>";
 //加载导航按钮

$("#"+options.navigateid).html(navigatehtml) 

//隐藏所有的导航按钮
$.extend({
    "hidenavigates":function(){
        //遍历所有的导航按钮
        navigates.each(function(){
            $(this).hide();
        }) 
    } 
});
 
//显示导航按钮
$.extend({
    "shownavigate":function(currentnavigate){
        $.hidenavigates();
        //当前按钮如果小于要求一次显示按钮个数的,从0开始显示
        var begin = currentnavigate>=options.navigatecount?currentnavigate-parseInt(options.navigatecount):0;
        //这里保证从第二页开始,按钮的个数都是2*options.navigatecount
        if(begin>navigates.length-2*options.navigatecount){
        begin = navigates.length-2*options.navigatecount; 
        }
        //开始显示
        for(var i = begin;i < currentnavigate+parseInt(options.navigatecount);i++){
            $(navigates[i]).show();
        }
    } 
});

好了,基本的代码流程就是这样了,程序的源代码在附件中,具体的功能实现在源代码注释中已经解释的挺清楚了。对于闭包还有疑问的,可以查看我上一篇博客,谈谈javascript闭包。

总结

下面总结一下jQuery插件的基本要点。

• 插件的文件名推荐为 jquery.[插件名].js,例如jquery.color.js
• 所有的对象方法都应当附加到jQuery.fn对象上,而所有的全局函数都应当附加到jQuery对象本身上

• 在插件内部,this指向的是当前通过选择器获取的jQuery对象,而不像一般的方法那样,例如click()方法,内部的this指向的是DOM元素

• 可以通过this.each来遍历所有元素
• 所有的方法或函数插件,都应当以分号结尾,否则压缩时可能出问题,有的为了更加稳妥些,在插件的开始处加上一个分号
• 插件应该返回一个jQuery对象,这样可以保证插件的可链式操作。除非插件需要返回的是一些需要获取的量,例如字符串或者数组等
• 尽量利用闭包技巧历来避免变量名的冲突。


赞(0)
未经允许不得转载:工具盒子 » 分享“分页”插件的前端开发过程