事由:由于最近在测试开发的一个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-49及51-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 - showPageNumber到50 +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 www.56MAX.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(