不足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 {  get set ; } // 页号
 5       public  int  from {  get set ; } // 前一页号
 6       public  int  to {  get set ; } // 后一页号
 7       public  IList < object >  result {  get set ; } // 数据
 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个页码,根据页码值来判断是否需要加上最前页等链接。如下图。

不足80行,一种清晰而又简单通用的分页算法,你有这么想过吗?C#版 
我给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 ) // 从第三页起显示 « 不足80行,一种清晰而又简单通用的分页算法,你有这么想过吗?C#版 «上一页
 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 ) // 从倒数第三页起显示 下一页»不足80行,一种清晰而又简单通用的分页算法,你有这么想过吗?C#版 »
 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来为其加载样式表.

你可能感兴趣的:(C#)