[轉]不足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個頁碼,根據頁碼值來判斷是否需要加上最前頁等鏈接。如下圖。

 
我給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來為其加載樣式表.


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com