zoukankan      html  css  js  c++  java
  • [原创]开发一个适合Ajax+JSON+jQuery环境使用的多功能页码栏——jPagerBar1.1.1

       Demo:http://www.senparc.com/WebTools.xhtml/JPagerBar 
       jPagerBar1.2已发布,升级说明及Demo、源代码下载请见:http://www.cnblogs.com/szw/archive/2009/08/27/1555201.html
       
        事由:由于最近在测试开发的一个ASP.NET MVC的项目需要用到页码栏(并且需要用到AJAX+JSON传输数据),而微软发布的.NET3.5 CTP MVCTOOLKIT里面又没有提供,网上找了下似乎也没有太称心的,于是就自己动手做一个。

    由于这个项目用到页码栏的地方大多是后台,所以既然不考虑SEO,本着效率第一的原则,决定全部使用js(jQuery)+Ajax+JSON的模式。我把js开发框架确定在了jQuery上。起先想叫“jPager”,想起来好像JAVA已经有一个JPager了,那就叫jPagerBar

    先确定一下这个插件在项目中必须满足的几个要求:

    1、页数不确定,根据记录条数和每页显示记录数自动生成

    2、样式不确定,必须可以根据页面需要应用不同样式

    3、必须可以自动缩略多余的页码,比如总共有100页,当浏览第50页时,可以省略1-4951-100之间的部分页码,并且这个延伸显示的页码数量可以由自己设定

    4、提供“上一页”“下一页”按钮,并且可以自己设定对应的值或图形

    5、记录为空时,隐藏页栏,显示友好的空记录信息

    6、属于附加要求:由于该空间可能用于不提供AJAX/JSON数据的页面或者由于配合SEO需要,同时兼顾POST+AJAX方式和GET直接请求页面(如.aspx)两种方式,并且逻辑和输出尽量分离以便日后需要直接HTML输出时(SEO需要),由js转换为C#语言。

    7、同一页面中可以多次重复调用,互不影响,并兼容IE/FF

    这里先列出完成以上几点必须提供的API,然后我会把源代码全部发上来:

    调用:ShowPageBar([containerId] ,[url] , [attr]);

    解释:

    参数名称

    类型

    说明

    containerId

    字符串

    提供装载页码栏的容器标签的客户端ID(用于定位,如div

    url

    字符串

    如果使用GET方法请求页面(最普通的页码栏换页方式),提供需要请求的URL(如果为POST,此url可为空值,有页面指定,稍后源代码中可见)

    attr

    hashtable

    页码栏参数,为hash数据具体包括如下表“表二”

    表二 attr hash参数说明:

    [attr]参数名称

    类型

    说明

    style

    字符串

    css样式,默认”technorati”等,可自己设置(我的示例中使用了网上提供的一套Web2.0的样式,大家也可以自己定制)

    totalCount

    整数

    总记录条数

    pageCount

    整数

    没页显示记录条数,默认为20

    showPageNumber

    整数

    缩略显示页码的阀值(如页码为50,则相邻只显示50 -  showPageNumber50   +showPageNumber的页码),默认为3

    currentPageIndex

    整数

    当前页码

    onclick

    字符串

    页码单击事件(如果采用单击事件,并且包含“return false”字段,则url将被忽略),插件会把“{pageindex}”自动替换为当前页码

    barMark

    字符串

    数据显示区域的Mark标签(<a name=[ barMark]></a>),备用

    noRecordTip

    字符串

    如果没有记录,显示的友好提示

    preWord

    字符造

    “上一页”按钮显示的字样

    nextWord

    字符串

    “下一页”按钮显示的字样

    jQuery源代码如下(PageBar-1.1.1.js):
    /*
     插件名称:jPagerBar
     主要功能:配合AJAX/JSON等响应方式及数据格式,自动生成页码栏。可以在同一网页中重复使用,互不影响。
                   API包括:
                   页码栏容器ID、GET请求URL
                   以及:页码栏样式、记录总数、每页显示记录数、显示相邻页码数量阀值、当前页、onclick事件、
                   页码栏定位标签、无记录提示、“上一页”“下一页”按钮的表现文字(或HTML)。
     当前版本号:1.1.1
     发布日期:2008/2/22

             作者:TNT2 (SZW on cnblogs  - szw.cnblogs.com)  QQ:63408537(加位好友请说明来意)   Email/MSN:szw2003@163.com    
                   http://www.Senparc.com
             
    版权及相关说明:
    1、作者对此插件保留所有权利。本插件本着开源、交流、共同进步的宗旨,以免费形式为大家无偿提供。修改、引用请保留以上说明信息,否则将视同为主动盗用本插件。
    2、为保证本插件的完整性、安全性和版本统一性,谢绝任何单位和个人将此插件代码修改后以个人名义或“jPagerBar”及类似名称发布,一旦发现,作者将不遗余进行力地进行追查、打击、曝光
    3、作者对此插件保留最终解释权。
             
             
    如有任何问题或意见、建议,欢迎与作者取得联系!让我们共同进步!
    ======================================================================================================================
    */


    function ShowPageBar(containerId , url , attr)
    {

        
    var style = (attr["style"== null)? "technorati" : attr["style"];//class样式
        var totalCount =( attr["totalCount"]==null ||  attr["totalCount"== 0? 0 :  attr["totalCount"];;//parseInt()//总记录条数
        var pageCount = (attr["pageCount"== null || attr["pageCount"== 0? 20 : attr["pageCount"];//attr["pageCount"];//每页记录数
        var showPageNumber = (attr["showPageNumber"== null || attr["showPageNumber"== 0? 20 : attr["showPageNumber"];//attr["showPageNumber"];//显示页码数量
        var currentPageIndex = attr["currentPageIndex"];//当前页
        var onclick = attr["onclick"];//onclick参数,如果包含“return false”,则连接转为跳到barMark(暂留接口,其实return false后一般情况下href将失效。)
        var barMark = attr["mark"];//onclick后跳转到的<a name="barMark"></a>标签
        var noRecordTip = attr["noRecordTip"];//没有记录提示(支持HTML)
        var preWord = (attr["preWord"== null)? " < " : attr["preWord"];//上一条记录文字,默认为“ < ”
        var nextWord = (attr["nextWord"== null)? " > " : attr["nextWord"];//下一条记录文字,默认为“ > ”
        
        
    //输出设置
        var barID = containerId + "_pageBar";
        
    //var barDiv = $("#"+barID);
        //添加PageBar层
        $("#"+containerId).html("<div id=\"" + barID + "\" class=\"" + style + "\"></div>");
        
    //输出设置 结束
        
        
    //如果没有记录,返回空记录提示
        if(totalCount==0)
        
    {
            $(
    "#"+barID).html(noRecordTip);
            
    return false;
        }

        
        pageCount 
    = (pageCount == null || pageCount == 0? 20 : pageCount;//每页显示记录数
        var totalPage = parseInt((totalCount-1/ pageCount) +1;//总页数
        
        showPageNumber 
    = (showPageNumber == null || showPageNumber == 0? 3 : showPageNumber;
        currentPageIndex 
    = (currentPageIndex == null || currentPageIndex <= 0 || currentPageIndex > totalPage) ? 1 : currentPageIndex;

        
    var backPageStyle = (currentPageIndex <= 1? "disabled" : "";
        
    var nextPageStyle = (currentPageIndex >= totalPage) ? "disabled" : "";

        
    var firstDisplayPageEnd = 0;//从第1页显示到xx页
        var bodyDisplayPageStart = 0;//当前页临近最左页码
        var bodyDisplayPageEnd = 0;//当前页临近最右页码
        var endDisplayPageStart = 0;//从第xx页显示到最后一页

        
    //设定 bodyDisplayPageStart
        bodyDisplayPageStart = (currentPageIndex - showPageNumber <= 1? 1 : currentPageIndex - showPageNumber; // (ViewData.pageIndex - ViewData.showPageNumber <= ViewData.showPageNumber) ? ViewData.showPageNumber + 1 : ViewData.pageIndex - ViewData.showPageNumber;

        
    //设定 bodyDisplayPageEnd
        bodyDisplayPageEnd = (currentPageIndex + showPageNumber >= totalPage) ? totalPage : currentPageIndex + showPageNumber;


        
    //设定 firstDisplayPageEnd
        if(bodyDisplayPageStart > 1)
        
    {
            
    if(bodyDisplayPageStart - showPageNumber <= 1)
                firstDisplayPageEnd 
    = bodyDisplayPageStart - 1;
            
    else
                firstDisplayPageEnd 
    = showPageNumber;
        }

        
    else
        
    {
            firstDisplayPageEnd 
    = 0;
        }

        
        
    //设定 endDisplayPageStart
        if(bodyDisplayPageEnd < totalPage)
        
    {
            
    if(bodyDisplayPageEnd + showPageNumber >= totalPage)
                endDisplayPageStart 
    = bodyDisplayPageEnd + 1;
            
    else
                endDisplayPageStart 
    = totalPage - showPageNumber + 1;
        }

        
    else
        
    {
            endDisplayPageStart 
    = totalPage + 1;
        }

        
        
    /********  备用算法 Start  ********/

    //    //设定 firstDisplayPageEnd
    //
        if (currentPageIndex - showPageNumber > 0 && bodyDisplayPageStart > currentPageIndex - showPageNumber)
    //
            firstDisplayPageEnd = (showPageNumber >= totalPage) ? 0 : showPageNumber;
    //
        else
    //
            firstDisplayPageEnd = 0; 

    //    //设定 endDisplayPageStart
    //
        if (bodyDisplayPageEnd < totalPage)
    //
            endDisplayPageStart = (bodyDisplayPageEnd + showPageNumber < totalPage) ?  totalPage- showPageNumber + 1 : totalPage+1;
    //
        else
    //
            endDisplayPageStart = totalPage+1;
    //
        
    //
        //alert(bodyDisplayPageEnd +"<" +totalCount +"- "+showPageNumber);
    //
        ////设定补充首尾
    //
        if(bodyDisplayPageStart > 1 && firstDisplayPageEnd == 0)
    //
            firstDisplayPageEnd = (bodyDisplayPageStart > showPageNumber)? showPageNumber : bodyDisplayPageStart - 1;
    //
        if(bodyDisplayPageEnd < totalPage && endDisplayPageStart > totalPage)
    //
            endDisplayPageStart = (bodyDisplayPageEnd < totalPage - showPageNumber)? totalCount - showPageNumber + 1 : bodyDisplayPageEnd + 1;//MS第一个判断有点多余    TNT2
    /********  备用算法 End  ********/

        
    //页面参数设定结束

        
    //开始输出
         //alert($("#"+barID).html());

        
    // 上一条
        if(currentPageIndex <= 1)
            $(
    "<span class=\"" + backPageStyle + "\">" + preWord + "</span>").appendTo($("#"+barID));
        
    else
            $(GetPageLink(currentPageIndex
    -1,currentPageIndex,preWord,onclick,url,barMark)).appendTo($("#"+barID));
            

        
    //first
        for (var i = 1; i <= firstDisplayPageEnd; i++)
            $(GetPageLink(i,currentPageIndex,i,onclick,url,barMark)).appendTo($(
    "#"+barID));
            
        
    //省略号
        if (firstDisplayPageEnd + 1 < bodyDisplayPageStart)
            $(
    "<span> </span>").appendTo($("#"+barID));
            
        
    //body
        for (var i = bodyDisplayPageStart; i <= bodyDisplayPageEnd; i++)
            $(GetPageLink(i,currentPageIndex,i,onclick,url,barMark)).appendTo($(
    "#"+barID));
            
        
    //省略号
        if (bodyDisplayPageEnd + 1 < endDisplayPageStart)
            $(
    "<span> </span>").appendTo($("#"+barID));
       
        
    //end
         for (var i = endDisplayPageStart; i <= totalPage; i++)
            $(GetPageLink(i,currentPageIndex,i,onclick,url,barMark)).appendTo($(
    "#"+barID));
            
        
    // > 
        if(currentPageIndex >= totalPage)
            $(
    "<span class=\"" + nextPageStyle + "\">" + nextWord + "</span>").appendTo($("#"+barID));
        
    else
            $(GetPageLink(currentPageIndex 
    + 1 ,currentPageIndex,nextWord,onclick,url,barMark)).appendTo($("#"+barID));
            
         
    //alert($("#"+barID).html());
    }


    //页码标签链接
    function GetPageLink(linkPageIndex ,currentPageIndex,text,onclick,url,barMark)
    {
        
    var pageData = "?page=";//string.Format("{0}page=", (Request.QueryString.Count == 0) ? "?" : "&") + "{0}";//页码参数
        
        onclick 
    = (onclick != null)? "onclick=\"" + onclick + "\"" : "";
        onclick 
    = onclick.replace("{pageindex}",linkPageIndex);
        href 
    = (onclick != null && onclick.indexOf("return false"!= -1)?"href=\"#" + barMark + "\" ":"href=\"" + url + pageData + linkPageIndex + "\" ";

        
    var linkHTML = "";
        
        
    if(linkPageIndex == currentPageIndex)
            linkHTML 
    =  "<span class=\"current\">" + text + "</span>";
        
    else
            linkHTML 
    = "<a " + href + onclick + ">" + text + "</a>";
              
        
    return linkHTML;
    }

    我们在HTML中这样调用:
        
        var pageCount = 15;//每页计数
        var totalRecord = 0;
        var pagerStyle = "flickr";//jPagerBar样式

    ShowPageBar("pageDataList1_Pager",//[containerId]
                       "
    <%= Request.Url.AbsolutePath %>",//[url]
                        {style:pagerStyle,mark:"pageDataList1Mark",
                        totalCount:msg.totalCount,showPageNumber:3,pageCount:pageCount,currentPageIndex:pageIndex,noRecordTip:"没有记录",preWord:"上一页",nextWord:"下一页",
                        onclick:"TurnToPage({pageindex});return false;"}//[attr]
                        );

    上面代码中的msg是我最后获取的JSON数据,msg.totalCount是一个总记录的计数,在这里您可以从msg.data(JSON数据列表)的计数获取,我在此多加这个totalCount只是为了防止测试过程中数据“失真”而引发的bug的掩盖,特此说明。

    一般我们还需要一个Handler来获取JSON数据(Handler1.ashx)已升级

    namespace jPagerBar.Handler
    {
        
    /// <summary>
        
    /// $codebehindclassname$ 的摘要说明
        
    /// </summary>

        [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo 
    = WsiProfiles.BasicProfile1_1)]
        
    public class Handler1 : IHttpHandler
        
    {

            
    public void ProcessRequest(HttpContext context)
            
    {

                
    //获取数据

                
    if (context.Request.RequestType == "POST")
                
    {
                    
    //设置行为参数
                    string action = context.Request.Form["action"].ToString();//动作
                    string kind = (action.StartsWith("g_")) ? action.Replace("g_"string.Empty) : string.Empty;//分类查找 前缀
                    string orderString = (context.Request.Form["orderby"].ToString());//排序
                    string order = "ascending";//排序:升序
                    string orderBy = (!string.IsNullOrEmpty(orderString)) ? orderString.Substring(0, orderString.Length - 2) : "ID";//要排序的字段,如果为空,默认为"ID"
                    if (orderString.EndsWith("_d"))
                    
    {
                        order 
    = "descending";//排序:降序
                    }


                    
    int pageCount = int.Parse(context.Request.Form["pageCount"].ToString());//每页显示记录数
                    int pageIndex = int.Parse(context.Request.Form["pageIndex"].ToString());//当前页
                    int skipRecord = (pageIndex - 1* pageCount;//跳过记录数


                    XElement dsXML 
    = CreateDataSorce();//创建并获取模拟数据源

                    
    //获取数据
                    var dsLinq =
                        (order 
    == "ascending"?
                        (from x 
    in dsXML.Descendants("DataTemp")
                         
    where ((!string.IsNullOrEmpty(kind)) ? (x.Element("Group").Value == kind) : (x.Element("Group").Value != null))
                         orderby x.Element(orderBy).Value ascending
                         select 
    new DataSourceModel()
                         
    {
                             ID 
    = x.Element("ID").Value,
                             Group 
    = x.Element("Group").Value,
                             Colum1 
    = x.Element("Colum1").Value,
                             Colum2 
    = x.Element("Colum2").Value,
                             Colum3 
    = x.Element("Colum3").Value
                         }
    )
                                  :
                        (from x 
    in dsXML.Descendants("DataTemp")
                         
    where ((!string.IsNullOrEmpty(kind)) ? (x.Element("Group").Value == kind) : (x.Element("Group").Value != null))
                         orderby x.Element(orderBy).Value descending
                         select 
    new DataSourceModel()
                         
    {
                             ID 
    = x.Element("ID").Value,
                             Group 
    = x.Element("Group").Value,
                             Colum1 
    = x.Element("Colum1").Value,
                             Colum2 
    = x.Element("Colum2").Value,
                             Colum3 
    = x.Element("Colum3").Value
                         }
    );

                    
    int totalCount = dsLinq.Count();//记录总数,在此只起到示范作用
                    
    //var dsFinalList = (order == "a") ?
                    
    //    dsLinq.OrderBy(x=>x.).Skip(skipRecord).Take(pageCount).ToList() :
                    
    //    dsLinq.OrderByDescending(orderby).Skip(skipRecord).Take(pageCount).ToList();

                    System.Text.StringBuilder sb 
    = new System.Text.StringBuilder();
                    sb.Append(
    "{");
                    sb.Append(
    "totalCount:");
                    sb.Append(totalCount.ToString());
                    sb.Append(
    ",data:");
                    sb.Append(ToJSON(dsLinq.Skip(skipRecord).Take(pageCount).ToList()));
                    sb.Append(
    "}");

                    context.Response.ContentType 
    = "text/plain";
                    context.Response.Write(sb.ToString());
                    context.Response.End();
                }


            }



            
    //创建数据源(用XML模拟)
            private XElement CreateDataSorce()
            
    {
                
    string dataSourceFilePath = HttpContext.Current.Server.MapPath("~/App_Data/DataSource.xml");

                
    if (!File.Exists(dataSourceFilePath))
                
    {
                    
    //设置模拟数据源
                    XElement dsInfos = new XElement("jPagerBar");
                        Random rdn 
    = new Random();
                    
    for (int i = 1; i <= 300; i++)
                    
    {
                        
    //分类数据(模拟)
                        
    //string[] groups = new string[] { "G1", "G2", "G3", "G4" };
                        string guid=Guid.NewGuid().ToString().Replace("-","");//用Guid产生随机代码
                        
    //生成模拟数据
                        XElement dsInfo = new XElement("DataTemp",
                       
    new XElement("ID", i.ToString("000")),
                       
    new XElement("Group""Group"+rdn.Next(0,5).ToString()),
                       
    new XElement("Colum1",guid.Substring(0,3+ "_C1 in " + i.ToString()),
                       
    new XElement("Colum2", guid.Substring(3,3+ rdn.Next(100).ToString() + "_C2 in " + i.ToString()),
                       
    new XElement("Colum3", guid.Substring(6,3+ rdn.Next(100).ToString() + "_C3 in " + i.ToString())
                       );
                        dsInfos.Add(dsInfo);
    //填充数据
                    }


                    
    //保存
                    dsInfos.Save(dataSourceFilePath);
                }


                
    return XElement.Load(dataSourceFilePath);
            }


            
    public static string ToJSON(object obj)
            
    {
                JavaScriptSerializer serializer 
    = new JavaScriptSerializer();
                
    return serializer.Serialize(obj);
            }


            
    //private static void GetJSON(XElement dsXML)
            
    //{
            
    //    var dsLinq = (from x in dsXML.Descendants("DataTemp")
            
    //                  select new DataSourceModel()
            
    //                  {
            
    //                      ID = x.Element("ID").Value,
            
    //                      Group = x.Element("Group").Value,
            
    //                      Colum1 = x.Element("Colum1").Value,
            
    //                      Colum2 = x.Element("Colum2").Value,
            
    //                      Colum3 = x.Element("Colum3").Value
            
    //                  });
            
    //    int totalCount = dsLinq.Count();//记录总数,在此只起到示范作用,客户端的记录总数可以从JSON数据的data计数获取
            
    //    System.Text.StringBuilder sb = new System.Text.StringBuilder();
            
    //    sb.Append("{");
            
    //    sb.Append("totalCount:");
            
    //    sb.Append(totalCount.ToString());
            
    //    sb.Append(",data:");
            
    //    sb.Append(ToJSON(dsLinq.ToList()));
            
    //    sb.Append("}");
            
    //}



            
    public bool IsReusable
            
    {
                
    get
                
    {
                    
    return false;
                }

            }

        }


        
    //数据源结构
        public class DataSourceModel
        
    {
            
    public string ID getset; }
            
    public string Group getset; }
            
    public string Colum1 getset; }
            
    public string Colum2 getset; }
            
    public string Colum3 getset; }
        }

    }



    上面我用XML模拟了一个数据源,正好顺便尝试了一下Linq to XML:)如果您是使用.NET2.0的话,也可改成XMLDocument的方式或者从自己的数据源获取。

    这里我们看一下基本效果:
    基本状态:



    如果超过相邻页数地阀值的页码用...替代:

    下面我们升级一下,可以自定义没页显示得条数和跳至的页码:


    光这样当然是不够的,如果用户输入了无效的值,会引发无效的服务器响应,我们需要在客户端就过滤:

    一共300条数据,每页10条,只能显示30页,要31页当然就错了。当然这里我的验证过程只是提供了一条思路,还可以有更多的丰富。(咦?光影魔术手不注册还会有水印?)

    刚才我说的需要能自定义样式,当然也不能少:


    或者这样:

    或者这样:



    ========以下为新增功能

    新增筛选、排序功能




    这个项目是开源的,大家可以在这里下载(Webforms):/Files/szw/jPagerBar.rar

    友情提醒一下:
    1、这个Demo默认为.net3.5,您也可体提取到别的.net版本中运行。
    2、这个项目的开发背景是ASP.NET MVC,为了比较直观,我用WebForms创建了这个Demo,如果有什么疏漏,请大家多多包涵,并且不吝指出其中的错误或者可以改进的地方。
    3、因为MVC和WebForms的输出方式有所不同,大家在这里可能看不到太多和.NET有关的东西,对应的
    .ascx文件我会在jPagerBar最终版本发布后,发布上来,当然大家也可以做成UI。

    这里再发布一个ASP.NET MVC V1.0环境的Demo(2009-8-11更新):/Files/szw/jPagerBar-MVCv1.0.rar
    jPagerBar in MVC Demo:http://www.senparc.com/WebTools.xhtml/JPagerBar

    做这个demo有点匆忙,希望对大家有用,十分期待大家的建议,谢谢!

    转载请注明出处和作者,谢谢!
    作者:JeffreySu / QQ:498977166
    博客:http://szw.cnblogs.com/

    Senparc官方教程《微信开发深度解析:微信公众号、小程序高效开发秘籍》,耗时2年精心打造的微信开发权威教程,点击这里,购买正版
    
微信开发深度解析:微信公众号、小程序高效开发秘籍

    Senparc 官方微信开发视频教程:《微信公众号+小程序快速开发》,点击这里点击观看
    Senparc 官方微信开发视频教程:《微信公众号+小程序快速开发》
  • 相关阅读:
    C语言 sprintf 函数 C语言零基础入门教程
    C语言 printf 函数 C语言零基础入门教程
    C语言 文件读写 fgets 函数 C语言零基础入门教程
    C语言 文件读写 fputs 函数 C语言零基础入门教程
    C语言 fprintf 函数 C语言零基础入门教程
    C语言 文件读写 fgetc 函数 C语言零基础入门教程
    C语言 文件读写 fputc 函数 C语言零基础入门教程
    C语言 strlen 函数 C语言零基础入门教程
    Brad Abrams关于Naming Conventions的演讲中涉及到的生词集解
    适配器模式
  • 原文地址:https://www.cnblogs.com/szw/p/1078238.html
Copyright © 2011-2022 走看看