無刷新分頁相信大家也看過不少,包括一些Jquery的分頁插件。之前做產品分頁的時候也下載研究過幾個,但是用現在的話說就是硬傷很多,不說代碼太多以及和自己數據庫很難對接,從SEO的角度考慮(必須要有有質量的鏈接),實在是就沒辦法用了。於是就決定自己寫了一個,一方面本人確實也稱不上高手,還是那句話,貼出來供大家參考,另一方面,文采很差,所以盡量少說話,多解釋代碼。
說明
無刷新的分頁主要分為三個步驟
步驟 A:數據庫分頁查詢
方法A1
方法A2
步驟B:后台分頁處理
步驟B1
步驟B2
步驟C:前台分頁調用。
步驟C1
步驟C2
慣例結尾會把實例附上。
步驟A :數據庫分頁查詢
這里提供兩種方法
方法A1:SQL SERVER自帶的分頁查詢語法
用我們這邊的產品數據庫做實例:查詢產品表Product中產品名(ProductName)中帶S的的第一頁數據,限制每頁個數為10,代碼:
declare @pageIndex int--頁數索引 declare @keyWord varchar(50)--搜索關鍵詞 declare @pageCount int--每頁數據個數 set @pageIndex=1 set @keyWord='S' set @pageCount=10; with Row as(SELECT row_number() over( order by addtime) as Num,AddTime,ProductName from Product where ProductName like '%'+@keyWord+'%' ) select top 10 * from Row where Num>(@pageIndex-1) * @pageCount and Num<= @pageIndex* @pageCount
結果返回一個DatatTable。這是一種比較簡單的方法,代碼也比較少,當然,支持的功能也有限,如果只是想簡單的實現分頁功能,可以考慮一下。
方法A2:SQL SERVER分頁存儲過程
此存儲過程是我在網上搜到的,具體地址我也記不清了,剛才在百度上搜了一下竟然沒搜到,在這里只能向作者說聲抱歉,貼一下你的代碼,如果有人能找到作者的原貼請留言發下地址,我會及時貼上去的。

CREATE PROC [dbo].[P_viewPage] @TableName VARCHAR(200), --表名 @FieldList VARCHAR(2000), --顯示列名,如果是全部字段則為* @PrimaryKey VARCHAR(100), --單一主鍵或唯一值鍵 @Where VARCHAR(2000), --查詢條件不含'where'字符,如id>10 and len(userid)>9 @Order VARCHAR(1000), --排序不含'order by'字符,如id asc,userid desc,必須指定asc或desc --注意當@SortType=3時生效,記住一定要在最后加上主鍵,否則會讓你比較郁悶 @SortType INT, --排序規則1:正序asc 2:倒序desc 3:多列排序方法 @RecorderCount INT, --記錄總數0:會返回總記錄 @PageSize INT, --每頁輸出的記錄數 @PageIndex INT, --當前頁數 @TotalCount INT OUTPUT, --記返回總記錄 @TotalPageCount INT OUTPUT --返回總頁數 AS SET NOCOUNT ON IF ISNULL(@TotalCount,'') = '' SET @TotalCount = 0 SET @Order = RTRIM(LTRIM(@Order)) SET @PrimaryKey = RTRIM(LTRIM(@PrimaryKey)) SET @FieldList = REPLACE(RTRIM(LTRIM(@FieldList)),' ','') WHILE CHARINDEX(', ',@Order) > 0 OR CHARINDEX(' ,',@Order) > 0 BEGIN SET @Order = REPLACE(@Order,', ',',') SET @Order = REPLACE(@Order,' ,',',') END IF ISNULL(@TableName,'') = '' OR ISNULL(@FieldList,'') = '' OR ISNULL(@PrimaryKey,'') = '' OR @SortType < 1 OR @SortType >3 OR @RecorderCount < 0 OR @PageSize < 0 OR @PageIndex < 0 BEGIN PRINT('ERR_00') RETURN END IF @SortType = 3 BEGIN IF (UPPER(RIGHT(@Order,4))!=' ASC' AND UPPER(RIGHT(@Order,5))!=' DESC') BEGIN PRINT('ERR_02') RETURN END END DECLARE @new_where1 VARCHAR(1000) DECLARE @new_where2 VARCHAR(1000) DECLARE @new_order1 VARCHAR(1000) DECLARE @new_order2 VARCHAR(1000) DECLARE @new_order3 VARCHAR(1000) DECLARE @Sql VARCHAR(8000) DECLARE @SqlCount NVARCHAR(4000) IF ISNULL(@where,'') = '' BEGIN SET @new_where1 = ' ' SET @new_where2 = ' WHERE ' END ELSE BEGIN SET @new_where1 = ' WHERE ' + @where SET @new_where2 = ' WHERE ' + @where + ' AND ' END IF ISNULL(@order,'') = '' OR @SortType = 1 OR @SortType = 2 BEGIN IF @SortType = 1 BEGIN SET @new_order1 = ' ORDER BY ' + @PrimaryKey + ' ASC' SET @new_order2 = ' ORDER BY ' + @PrimaryKey + ' DESC' END IF @SortType = 2 BEGIN SET @new_order1 = ' ORDER BY ' + @PrimaryKey + ' DESC' SET @new_order2 = ' ORDER BY ' + @PrimaryKey + ' ASC' END END ELSE BEGIN SET @new_order1 = ' ORDER BY ' + @Order END IF @SortType = 3 AND CHARINDEX(','+@PrimaryKey+' ',','+@Order)>0 BEGIN SET @new_order1 = ' ORDER BY ' + @Order SET @new_order2 = @Order + ',' SET @new_order2 = REPLACE(REPLACE(@new_order2,'ASC,','{ASC},'),'DESC,','{DESC},') SET @new_order2 = REPLACE(REPLACE(@new_order2,'{ASC},','DESC,'),'{DESC},','ASC,') SET @new_order2 = ' ORDER BY ' + SUBSTRING(@new_order2,1,LEN(@new_order2)-1) IF @FieldList <> '*' BEGIN SET @new_order3 = REPLACE(REPLACE(@Order + ',','ASC,',','),'DESC,',',') SET @FieldList = ',' + @FieldList WHILE CHARINDEX(',',@new_order3)>0 BEGIN IF CHARINDEX(SUBSTRING(','+@new_order3,1,CHARINDEX(',',@new_order3)),','+@FieldList+',')>0 BEGIN SET @FieldList = @FieldList + ',' + SUBSTRING(@new_order3,1,CHARINDEX(',',@new_order3)) END SET @new_order3 = SUBSTRING(@new_order3,CHARINDEX(',',@new_order3)+1,LEN(@new_order3)) END SET @FieldList = SUBSTRING(@FieldList,2,LEN(@FieldList)) END END SET @SqlCount = 'SELECT @TotalCount=COUNT(*),@TotalPageCount=CEILING((COUNT(*)+0.0)/' + CAST(@PageSize AS VARCHAR)+') FROM ' + @TableName + @new_where1 IF @RecorderCount = 0 BEGIN EXEC SP_EXECUTESQL @SqlCount,N'@TotalCount INT OUTPUT,@TotalPageCount INT OUTPUT', @TotalCount OUTPUT,@TotalPageCount OUTPUT END ELSE BEGIN SELECT @TotalCount = @RecorderCount END IF @PageIndex > CEILING((@TotalCount+0.0)/@PageSize) BEGIN SET @PageIndex = CEILING((@TotalCount+0.0)/@PageSize) END IF @PageIndex = 1 OR @PageIndex >= CEILING((@TotalCount+0.0)/@PageSize) BEGIN IF @PageIndex = 1 --返回第一頁數據 BEGIN SET @Sql = 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM ' + @TableName + @new_where1 + @new_order1 END IF @PageIndex >= CEILING((@TotalCount+0.0)/@PageSize) --返回最后一頁數據 BEGIN SET @Sql = 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM (' + 'SELECT TOP ' + STR(ABS(@PageSize*@PageIndex-@TotalCount-@PageSize)) + ' ' + @FieldList + ' FROM ' + @TableName + @new_where1 + @new_order2 + ' ) AS TMP ' + @new_order1 END END ELSE BEGIN IF @SortType = 1 --僅主鍵正序排序 BEGIN IF @PageIndex <= CEILING((@TotalCount+0.0)/@PageSize)/2 --正向檢索 BEGIN SET @Sql = 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM ' + @TableName + @new_where2 + @PrimaryKey + ' > ' + '(SELECT MAX(' + @PrimaryKey + ') FROM (SELECT TOP ' + STR(@PageSize*(@PageIndex-1)) + ' ' + @PrimaryKey + ' FROM ' + @TableName + @new_where1 + @new_order1 +' ) AS TMP) '+ @new_order1 END ELSE --反向檢索 BEGIN SET @Sql = 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM (' + 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM ' + @TableName + @new_where2 + @PrimaryKey + ' < ' + '(SELECT MIN(' + @PrimaryKey + ') FROM (SELECT TOP ' + STR(@TotalCount-@PageSize*@PageIndex) + ' ' + @PrimaryKey + ' FROM ' + @TableName + @new_where1 + @new_order2 +' ) AS TMP) '+ @new_order2 + ' ) AS TMP ' + @new_order1 END END IF @SortType = 2 --僅主鍵反序排序 BEGIN IF @PageIndex <= CEILING((@TotalCount+0.0)/@PageSize)/2 --正向檢索 BEGIN SET @Sql = 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM ' + @TableName + @new_where2 + @PrimaryKey + ' < ' + '(SELECT MIN(' + @PrimaryKey + ') FROM (SELECT TOP ' + STR(@PageSize*(@PageIndex-1)) + ' ' + @PrimaryKey +' FROM '+ @TableName + @new_where1 + @new_order1 + ') AS TMP) '+ @new_order1 END ELSE --反向檢索 BEGIN SET @Sql = 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM (' + 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM ' + @TableName + @new_where2 + @PrimaryKey + ' > ' + '(SELECT MAX(' + @PrimaryKey + ') FROM (SELECT TOP ' + STR(@TotalCount-@PageSize*@PageIndex) + ' ' + @PrimaryKey + ' FROM ' + @TableName + @new_where1 + @new_order2 +' ) AS TMP) '+ @new_order2 + ' ) AS TMP ' + @new_order1 END END IF @SortType = 3 --多列排序,必須包含主鍵,且放置最后,否則不處理 BEGIN IF CHARINDEX(',' + @PrimaryKey + ' ',',' + @Order) = 0 BEGIN PRINT('ERR_02') RETURN END IF @PageIndex <= CEILING((@TotalCount+0.0)/@PageSize)/2 --正向檢索 BEGIN SET @Sql = 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM ( ' + 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM ( ' + ' SELECT TOP ' + STR(@PageSize*@PageIndex) + ' ' + @FieldList + ' FROM ' + @TableName + @new_where1 + @new_order1 + ' ) AS TMP ' + @new_order2 + ' ) AS TMP ' + @new_order1 END ELSE --反向檢索 BEGIN SET @Sql = 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM ( ' + 'SELECT TOP ' + STR(@PageSize) + ' ' + @FieldList + ' FROM ( ' + ' SELECT TOP ' + STR(@TotalCount-@PageSize*@PageIndex+@PageSize) + ' ' + @FieldList + ' FROM ' + @TableName + @new_where1 + @new_order2 + ' ) AS TMP ' + @new_order1 + ' ) AS TMP ' + @new_order1 END END END PRINT(@Sql) EXEC(@Sql)
各個參數作者都做了解釋,只要給各個參數賦值,執行存儲過程就可以得到一個相應的Datatable。
步驟B:后台分頁處理
分頁處理方法也就是前台ajax調用的方法,有兩個參數,參數PageIndex int類型,為當前頁數;參數key,搜索產品關鍵詞。方法返回List<String>類型,方法聲明代碼(.NET):
[WebMethod] public static List<String> LoadProduct(int PageIndex, String key) { List<String> list = new List<String>(); //.. return list; }
實例中用的數據庫查詢方法是A2方法SQL SERVER分頁存儲過程,本人親測百萬條數據情況下執行這個存儲過程沒什么壓力。在分頁處理方法中聲明參數的代碼:
string TableName = "VProducts";//表名 string FieldList = "Pictures,ProductName,IDPlus,addtime";//字段集合 string PrimaryKey = "IDPlus";//主鍵 string Order = "IDPlus desc";//排序 int SortType = 2;//排序規則 1:正序asc 2:倒序desc 3:多列排序方法 int RecorderCount = 0;//字段集合 int PageSize = 4;//每頁輸出的記錄數 String where = "ProductName like '%" + key + "%'"; SqlParameter[] paras = { new SqlParameter("@TableName",TableName), new SqlParameter("@FieldList",FieldList), new SqlParameter("@TotalPageCount",SqlDbType.Int), new SqlParameter("@TotalCount",SqlDbType.Int), new SqlParameter("@PrimaryKey",PrimaryKey), new SqlParameter("@Where",where), new SqlParameter("@Order",Order), new SqlParameter("@SortType",SortType), new SqlParameter("@RecorderCount",RecorderCount), new SqlParameter("@PageSize",PageSize), new SqlParameter("@PageIndex",PageIndex) }; paras[2].Direction = ParameterDirection.InputOutput;//設置 paras[2].Value = 0; paras[3].Direction = ParameterDirection.InputOutput;//設置 paras[3].Value = 0; DataTable DT = DBHelper.GetDataTable("P_viewPage", paras);//執行存儲過程得到Datatable
通過執行存儲過程得到一個DataTable。之后要進行兩個步驟操作。
步驟B1 遍歷這個datatable,然后填充到一個HTML模板里。
這個HTML模板就是顯示單條產品的HTML元素,如實例中把每個產品顯示在一個li里
String Temp = @"<li class='last'> <div class='pic'> <a href='javascript:void(0)'> <img width='160' src='{0}' /></a> </div> <div class='name'> <a href='javascript:void(0)'>{1}</a> </div> </li>";
然后就可以填充了,代碼:
StringBuilder SB = new StringBuilder();//建議用StringBuilder int PageNum = Convert.ToInt32(paras[2].Value);//輸出參數 總頁數 int ProductCount = Convert.ToInt32(paras[3].Value);//輸出參數 總個數 if (DT != null && DT.Rows.Count != 0) { for (int i = 0; i < DT.Rows.Count; i++) { SB.AppendFormat(Temp, DT.Rows[i]["Pictures"].ToString(), DT.Rows[i]["ProductName"].ToString()); } }
存儲過程還有兩個輸出參數,分別記錄總頁數和總個數。
步驟B2
步驟B1已經得到了該頁數的所有數據,步驟B2是關於頁數的操作,如圖:
這一塊的代碼要根據當前頁數及總頁數生產,並且為每頁分配一個可用連接,當在瀏覽器中輸入該連接,會加載該頁的產品。代碼:

StringBuilder SBPage = new StringBuilder(); if (PageNum != 0) { #region 分頁顯示 string path = System.Web.HttpContext.Current.Request.UrlReferrer + (key != "" ? "&" : "?") + "pageindex=";//判斷是否有參數key string strFirstTemp = "<li><a onclick='return getList(1);' href='" + path + "1'>首頁</a></li>";//拼接url string strLastTemp = "<li><a onclick='return getList(" + (PageNum).ToString() + ");' href='" + path + (PageNum).ToString() + "' >尾頁</a></li>"; string strFrontTemp = "<li><a onclick='return getList(" + (PageIndex - 1).ToString() + ");' href='" + path + (PageIndex - 1).ToString() + "' >上一頁</a></li>"; string strNextTemp = "<li><a onclick='return getList(" + (PageIndex + 1).ToString() + ");' href='" + path + (PageIndex + 1).ToString() + "' >下一頁</a></li>"; string strCurrentTemp = "<li><span >{0}</span></li>"; string strPageTemp = "<li><a onclick='return getList({0});' href='" + path + "{0}'>{0}</a></li>"; //若頁數=1 if (PageNum == 1) { SBPage.AppendFormat(strCurrentTemp, 1); } else//若頁數大於1 { if (PageIndex == 1)//若當前頁=1 { SBPage.AppendFormat(strCurrentTemp, 1); if (PageNum <= 10)//若總頁數小於等於10 { for (int i = 2; i <= PageNum; i++) { SBPage.AppendFormat(strPageTemp, i); } } else//若總頁數大於10 { for (int i = 2; i <= 10; i++) { SBPage.AppendFormat(strPageTemp, i); } } SBPage.Append(strNextTemp); SBPage.Append(strLastTemp); } else if (PageIndex == PageNum)//若當前頁等於總頁數 { SBPage.Append(strFirstTemp); SBPage.Append(strFrontTemp); if (PageNum <= 10)//若總頁數小於等於10 { for (int i = 1; i < PageNum; i++) { SBPage.AppendFormat(strPageTemp, i); } } else//若總頁數大於10 { for (int i = (PageNum - 9); i < PageNum; i++) { SBPage.AppendFormat(strPageTemp, i); } } SBPage.AppendFormat(strCurrentTemp, PageNum); } else//若當前頁數不等於1且不等於總頁數 { if (1 < PageNum && PageNum <= 10)//若總頁數大於1小於等於10 { SBPage.Append(strFirstTemp); SBPage.Append(strFrontTemp); for (int i = 1; i <= PageNum; i++) { if (PageIndex == i) { SBPage.AppendFormat(strCurrentTemp, i); } else { SBPage.AppendFormat(strPageTemp, i); } } SBPage.Append(strNextTemp); SBPage.Append(strLastTemp); } else//若總頁數大於10 { if (1 < PageIndex && PageIndex <= 5)//若當前頁數大於1且小於等於5 { SBPage.Append(strFirstTemp); SBPage.Append(strFrontTemp); for (int i = 1; i <= 10; i++) { if (PageIndex == i) { SBPage.AppendFormat(strCurrentTemp, i); } else { SBPage.AppendFormat(strPageTemp, i); } } SBPage.Append(strNextTemp); SBPage.Append(strLastTemp); } else//若當前頁數大於5 { if (5 < PageIndex && PageIndex <= (PageNum - 5))//若當前頁數大於5且小於總頁數-5 { SBPage.Append(strFirstTemp); SBPage.Append(strFrontTemp); for (int i = (PageIndex - 4); i <= (PageIndex + 5); i++) { if (PageIndex == i) { SBPage.AppendFormat(strCurrentTemp, i); } else { SBPage.AppendFormat(strPageTemp, i); } } SBPage.Append(strNextTemp); SBPage.Append(strLastTemp); } else//若當前頁數小於總頁數-5 { SBPage.Append(strFirstTemp); SBPage.Append(strFrontTemp); for (int i = (PageNum - 9); i <= PageNum; i++) { if (PageIndex == i) { SBPage.AppendFormat(strCurrentTemp, i); } else { SBPage.AppendFormat(strPageTemp, i); } } SBPage.Append(strNextTemp); SBPage.Append(strLastTemp); } } } } } #endregion }
最后把得到的各種數據添加到聲明的list里,並返回給前台JS處理
list.Add(SB.ToString()); list.Add(SBPage.ToString()); list.Add(PageNum.ToString()); list.Add(ProductCount.ToString()); return list;
步驟C:前台分頁調用
同步步驟B2中的代碼已經看到返回的HTML元素中已經有了onclick事件,調用的是前台方法getList
我們來看看這個方法的代碼:
function getList(pageIndex) { $.ajax({ type: "POST", url: "/cnblog/ajax.aspx/LoadProduct", data: "{'PageIndex':'" + pageindex + "','key':'" + decodeURIComponent($.request("key")) + "'}", //搜索關鍵字,如果沒有則為空 contentType: "application/json; charset=utf-8", dataType: "json", success: function (result) { $(".productslist").html(result.d[0]); $(".paginator").html(result.d[1]); $(".pageCount").html(result.d[2]); $(".productCount").html(result.d[3]); }, error: function (result) { } }); return false;//一定要加return false。在ie里一個超鏈接有onclick事件也有href屬性,如果不加return false 點擊的時候會觸發事件后再跳轉 }
參數為pageIndex ,既頁數 ,所以當點擊返回的頁數連接時會調用這個方法,並且把頁數及搜索關鍵詞傳過去,傳過去之后得到的結果即為步驟B中LoadProduct方法的返回值。
我們來看看效果吧!
注意截圖上的文字解釋: