zoukankan      html  css  js  c++  java
  • 不足80行,一种清晰而又简单通用的分页算法,你有这么想过吗?C#版

    分页,是WEB开发中面对的最常见的编程,实现方法多种多样。我也不来评论这些方法的好坏。

    但我总感觉它们太复杂,不够清晰不够简单。我十分欣赏PHP中一个Pager.php分页类的算法。http://www.phpclasses.org/browse/file/288.html,作者不详。也在不同的项目中把这种思想转换成不同语言的分页类,你不妨也试试。

    这种算法的思路是这样的:

    1、把分页后的数据抽象为一个类,你可以把它想象成一个双向链表的一个结点。

    结构如下:

     1 //页类
     2 public class Page
     3 {
     4     public int pageno { getset; }//页号
     5     public int from { getset; }//前一页号
     6     public int to { getset; }//后一页号
     7     public IList<object> result { getset; }//数据
     8     public Page(int page)
     9     {
    10         this.pageno = page;
    11     }
    12 
    13 }

    2、编写一个Pager类来管理根据你的数据源计算总页码、当前页码的数据、生成用于导航的页码条。

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Text;
     4 
     5 public class Pager
     6 {
     7     int total_pages = 1;
     8     int elem_per_page = 10;
     9     int count_elements = 0;
    10     IList<object> arr = new List<object>();
    11     //创建函数
    12     public Pager(IList<object> arr, int per_page)
    13     {
    14         elem_per_page = per_page;
    15         count_elements = arr.Count;
    16         if ((this.count_elements % per_page) == 0)
    17         {
    18             total_pages = (int)(count_elements / per_page);
    19         }
    20         else
    21         {
    22             total_pages = (int)(count_elements / per_page) + 1;
    23         }
    24         this.arr = arr;
    25     }
    26 
    27     //计算出一页来
    28     public Page page(int pageno)
    29     {
    30         Page apage = new Page(pageno);
    31         int from = this.elem_per_page * (pageno - 1+ 1;
    32         int to = from + this.elem_per_page - 1;
    33         if (to > count_elements) { to = this.count_elements; }
    34 
    35         List<object> res = new List<object>();
    36         for (int i = (from - 1); i < to; i++)
    37         {
    38             res.Add(this.arr[i]);
    39         }
    40         apage.from = from;
    41         apage.to = to;
    42         apage.result = res;
    43         return apage;
    44     }
    45     //简单地生成页码
    46     public string PrintPageNumbers(int cp, string url)
    47     {
    48         string pageurl = "<div id=""paperindex"">";
    49         if (url.Contains("?")) { url += "&pageno="; } else { url += "?pageno="; }
    50         for (int i = 1; i < this.total_pages + 1; i++)
    51         {
    52             if (i != cp)
    53             {
    54                 pageurl = pageurl + "[<a href=""" + url + "" + i + """>" + i + "</a>]";
    55             }
    56             else
    57             {
    58                 pageurl = pageurl + "<span id=""current"">[" + i + "]</span>";
    59 
    60             }
    61         }
    62         return pageurl + "</div>";
    63     }
    64 }

    简单分析一下,创建函数根据每页显示数据条数计算出总页数,根据你取得的页码调用page(int)来取得那一页的page实例,page实例中包含它的页码,它上一页和下一页的页码,和分页完成后的数据。应用PrintPageNumbers()函数你就可以得到一个用于导航的索引条了。

    3、使用方法

     IList<object> list=BLL.News.getAll();//从业务层取数据

    Pager pager=new Pager(list,20);//从list取数据进行分页,每页20条.

    Page ap=pager.page(Int32.Parse(Request["pageno"]));//以GET方式获取需要显示的页号。

    Label1.Text=pager.PrintPageNumbers(Int32.Parse(Request["pageno"]), Request.FilePath.ToString());//向界面上写出导航条

    因为ap.result保存着分页后的数据,我们显示数据就有很多选择了。如果你是用table表达那你循环一下拆箱后把每个对象的属性输出一下,如果是用AJAX表达那你把对象列表转换成JSON或XML,传给AJAX页面。OK。分页达成。

    4、扩展

    如果你需要更漂亮的导航,可以覆写Pager类的PrintPageNumbers方法,我们对它进行扩展非常的容易。比如为实现以下效果。

    每次只显示5个页码,根据页码值来判断是否需要加上最前页等链接。如下图。

     
    我给Pager类加了以下的生成分页导航的函数。

      1 #region 后面是可扩展的页码显示方式,我实现了其它两种。
      2     /**
      3     * 生成前导串
      4     * 根据当前页号来生成是否有上一页或最前页
      5     * */
      6     public string get_prestr(int pageindex, string url)
      7     {
      8         string result = "<div id=""paperindex"">";
      9         if (url.Contains("?")) { url += "&pageno="; } else { url += "?pageno="; }
     10 
     11         if (pageindex > 1)
     12         {
     13 
     14             if (pageindex >= 3)//从第三页起显示 «  «上一页
     15             {
     16                 result += "<a href=""" + url + "1"">最前页</a>,<a href=""" + url + (pageindex - 1) + """>上一页</a>,";
     17             }
     18             else//第2页显示 «上一页
     19             {
     20                 result += "<a href=" + url + (pageindex - 1+ ">上一页</a>,";
     21             }
     22 
     23         }
     24         else
     25         {
     26 
     27         }
     28         return result;
     29     }
     30     /**
     31      * 生成中间数字串
     32      * 如总记13页当前页为5,每次显示5个页码
     33      * 则应该返回3,4,5,6,7
     34      * */
     35     public List<int> get_midpageno(int pageindex, int display_count)
     36     {
     37         List<int> l = new List<int>();
     38         int A = display_count / 2;//取中间值
     39         if (total_pages > display_count)
     40         {
     41             if (pageindex <= A)
     42             {
     43                 for (int i = 1; i < display_count + 1; i++)
     44                 {
     45                     l.Add(i);
     46                 }
     47             }
     48             if (pageindex > (total_pages - A))
     49             {
     50                 for (int i = total_pages - display_count + 1; i < total_pages + 1; i++)
     51                 {
     52                     l.Add(i);
     53                 }
     54             }
     55             if ((pageindex > A) && (pageindex <= (total_pages - A)))
     56             {
     57                 for (int i = pageindex - A; i < pageindex + A + 1; i++)
     58                 {
     59                     l.Add(i);
     60                 }
     61             }
     62         }
     63         else
     64         {
     65             for (int i = 1; i < total_pages + 1; i++)
     66             {
     67                 l.Add(i);
     68             }
     69 
     70         }
     71 
     72         return l;
     73     }
     74 
     75     /**
     76      * 生成后导串
     77      * 根据当前页码和总页码来判断是否显示最后页和后一页
     78      * */
     79     public string get_nextstr(int pageindex, string url)
     80     {
     81         //与前导串算法类似,所以先计算当前页是倒数第几页
     82         int toend = total_pages - pageindex + 1;
     83         string result = "";
     84         if (url.Contains("?")) { url += "&pageno="; } else { url += "?pageno="; }
     85 
     86         if (toend > 1)
     87         {
     88 
     89             if (toend >= 3)//从倒数第三页起显示 下一页» »
     90             {
     91                 result += "<a href=""" + url + (pageindex + 1) + """>下一页</a>,<a href=""" + url + total_pages + """>最后页</a>  ";
     92             }
     93             else//倒数第2页显示 下一页»
     94             {
     95                 result += "<a href=" + url + (pageindex + 1+ ">下一页</a>";
     96             }
     97 
     98         }
     99         else
    100         {
    101 
    102         }
    103         return result + "</div>";
    104     }
    105     /*
    106      * 一种生成固定显示页码数量的页码display_count最好是个奇数,这样可以保证当前页处于分页条的正中间
    107      * 生成的页码以一个ID为paperindex的div封装,当前页码ID为current,方便加载样式。
    108      * */
    109     public string PrintPageNumbers(int pageindex, string url, int display_count)
    110     {
    111 
    112         string originurl = url;
    113         string pageurl = "";
    114         if (url.Contains("?")) { url += "&pageno="; } else { url += "?pageno="; }
    115         pageurl += get_prestr(pageindex, originurl);//加入前导串
    116         //生成中间串
    117         foreach (int a in get_midpageno(pageindex, display_count))
    118         {
    119             if (a.Equals(pageindex))
    120             {
    121                 pageurl += "<span id=""current"">" + a + "</span>,";
    122             }
    123             else
    124             {
    125                 pageurl += "<a href=""" + url + a + """>" + a + "</a>,";
    126             }
    127         }
    128         pageurl += get_nextstr(pageindex, originurl);//加入后导串
    129         if (pageurl.EndsWith(",</div>")) { pageurl = pageurl.Replace(",</div>""</div>"); }
    130         return pageurl;
    131     }
    132     //显示总记录数和总页数
    133     public string PrintPageNumbers(int pageindex, string url, int display_count, bool todisplaytotalrecorder, bool todisplaytotalpages)
    134     {
    135         string result = "";
    136         if (todisplaytotalrecorder) { result += "<span id=""recordercount"">共有记录:" + this.arr.Count + "条</span>  "; }
    137         if (todisplaytotalpages) { result += "<span id=""pagecount"">共记:" + this.total_pages + "页</span>"; }
    138         return result + PrintPageNumbers(pageindex, url, display_count);
    139     }
    140     #endregion

    在调用这个函数生成的导航表达索引时,需要再配合一下简单的样式表。因为我在输出页码时给它加了ID属性,所以可以根据ID加载CSS。

    我给它配的是这样的。

    <style type="text/css">
    #paperindex{
    font:14px #000000;
    }
    #paperindex #current{
    border:1px solid #142A3B;
    background-color:B1D3EC;
    color:#000;

    }
    a,a:visited
    {
     text-decoration:none;
     color:#000;
     }
    a:hover
    {
        color:red;
     text-decoration:underline;
    }
    </style>

    总结:

    我借鉴PHP中常用的一个分页类paper.php网址[http://www.phpclasses.org/browse/file/288.html]
    的分页算法,PHP的作者不详,但分页算法十分清晰有效。
     DEMO:
      List<object> list=BLL.Customers.getAll();//从业务层或数据层取出数据列表
     Pager pager = new Pager(list, 20);//生成pager,数据从list中取,每页20条
     int currentpageindex=Int32.parse(Request["pageno"]);//GET方式获取pageno,pageno是类中定义的页码传参变量
      Page page = pager.page(currentpageindex);//
      然后就可以通过page.result来取到用于显示的当前页的List<object>数据
    再通过Pager的PrintPageNumbers方法来生成页码的字符串。
     提示:这是一个干净的类,主要从算法上简捷地实现分页。如果对性能要求较高,可以考虑将分页的数据源进行缓存来达到目的。这些没有考虑在此分页类中。
     提示:可以根据生成页码后的DIV的ID来为其加载样式表.

  • 相关阅读:
    flex 居中并两端对齐
    搭建Docker环境---私有仓库registry搭建
    搭建Docker环境---常用命令
    搭建Docker环境---Docker安装(centos7)
    搭建Docker环境---Docker概述
    Shell脚本
    安装webstrom2019
    mysql主从配置
    MySql5.7安装(centos 7)
    MySQL父子节点查询
  • 原文地址:https://www.cnblogs.com/lzhdim/p/1343845.html
Copyright © 2011-2022 走看看