ASP.NET MVC利用PagedList分页(二)PagedList+Ajax+JsRender
(原文)
昨天在ASP.NET MVC利用PagedList分页(一)的 最后一节提到,一个好的用户体验绝对不可能是点击下一页后刷新页面,所以今天来说说利用Ajax+PagedList实现无刷新(个人绝对局部刷新更准确 些)的分页。其实在PagedList.Mvc中早已经为我们提供好了Ajax分页的各种东东,但是这里我要自己写下。
实现思想:
1、客户端发送Ajax请求。2、服务器端响应请求并将响应结果回传给客户端。3、客户端接收响应结果并进行数据绑定。
实现方案:
大多数人都知道这个思想,但是面对一个陌生的环境,我不得不理一下思路然后再 讨论实现方案:1、利用Jquery Ajax发送分页请求。2、进行数据划分并利用SataticPagedList<T>(我个人比较喜欢这个,也可以用 ToPagedList)绑定。3、利用Jquery Ajax接收数据并进行数据绑定。ok,实现方案出炉,下面直接上代码:

//View:Views/Person/Ajax
<link href="/Content/PagedList.css" type="text/css" rel="Stylesheet" />
......
<script type="text/javascript" src="/Scripts/jquery-1.5.1.js"></script>
<script type="text/javascript">
$(function () {
getPersonByAjax(1);
});
//Ajax请求
var getPersonByAjax = function (pageNumber) {
$.ajax({
url: "/Person/AjaxPage?page=" + pageNumber,
type: "POST",
dataType: "json",
success: function (data) {
//接收数据(data)并绑定
var html = "";
$.each(data.persons, function (i, item) {
html += "<tr><td>" + item.FirstName + "</td><td>" + item.LastName +
"</td><td><a href='/Person/Edit/" + item.PersonID + "'>Edit</a> | <a href='/Person/Details/" +
item.PersonID + "'>Details</a> | <a href='/Person/Delete/" + item.PersonID + "'>Delete</a></td></tr>";
});
$("#personList").html(html);
},
error: function (result) {
alert(result.statusText);
},
complete: function (jqXHR) {
jqXHR = null;
}
});
}
</script> //Controller:PersonController
//响应Ajax请求
public ActionResult AjaxPage(int? page)
{
int pageIndex = page ?? 1;
int pageSize = 2;
int totalCount = 0;
var persons = GetPerson(pageIndex, pageSize, ref totalCount);
var personsAsIPageList = new StaticPagedList<Person>(persons, pageIndex, pageSize, totalCount);
return Json(new { persons = personsAsIPageList},JsonRequestBehavior.AllowGet);
} public List<Person> GetPerson(int pageIndex, int pageSize, ref int totalCount)
{
var persons = (from p in db.Persons
orderby p.PersonID descending
select p).Skip((pageIndex - 1) * pageSize).Take(pageSize);
totalCount = db.Persons.Count();
return persons.ToList();
}
(注:这里运用到了Json在服务器和客户端之间传递的知识额...我非常喜欢Json接收强类型对象,后头有机会慢慢谈下。)

在写“接收数据(data)并绑定之前”我还在天真的想,personAdIPagedList不会回吧HasPreviousPage、HasNextNextPage也传递过来呢?于是我用Fillder服务器端到底会传递什么回来,结果如下:

挂了,貌似他至传回了persons的json数据,那分页咋办呢?原来在IPagedList<T>中有个GetMetaData,他会返回一个PagedListMetaData对象,在这里进行了分页导航相关属性的分装:

添加分页导航
good,这下我可以完善我的代码了。 如下:

public ActionResult AjaxPage(int? page)
{
int pageIndex = page ?? 1;
int pageSize = 2;
int totalCount = 0;
var persons = GetPerson(pageIndex, pageSize, ref totalCount);
var personsAsIPageList = new StaticPagedList<Person>(persons, pageIndex, pageSize, totalCount);
return Json(new { persons = personsAsIPageList, pager = personsAsIPageList.GetMetaData() }, JsonRequestBehavior.AllowGet);
}


可以看到这里PagedList传回了所有的分页信息。所以可以做分页导航了:

//创建分页导航
var pager = data.pager;
html = "";
if (pager.HasPreviousPage) {
html += "<a href='#' onclick='getPersonByAjax(" + (pager.PageNumber - 1) + ");return false;'><<</a> <a href='#' onclick='getPersonByAjax(1);return false;'>< Prev</a>";
}
else {
html += "<< < Prev";
}
html += " ";
if (pager.HasNextPage) {
html += "<a href='#' onclick='getPersonByAjax(" + (pager.PageNumber + 1) + ");return false;'>Next ></a> <a href='#' onclick='getPersonByAjax(" + pager.PageCount + ");return false;'>>></a>";
}
else {
html += "Next > >>";
}
$("#pager").html(html);

将上面代码插入success中,分页就创建好了。当我正在高兴的时候我大概忘记了刚刚做字符串拼接的辛苦。冷静下来后我和PagedList提供的实例(好像忘了给地址,给一个:https://github.com/TroyGoode/PagedList)进行了对比,对比结果是我无比蛋疼。在其提供实例中用到了jquery.tmpl.js,原来我们真的不用做如此多的字符处啊拼接工作。
优化绑定
jquery.tmpl.js是一个模板插件,能够用对象或数据等对模板(包含html、css等标签和绑定表达式。)进行渲染,举个例子:"<li class='XXX' id='liTemplate'>${name}</li>"这就是一个模板,包含html、css和绑定表达式(${name}),现在我们只需利用:$.template("templateName",$('#liTemplate').html());$.tmpl(templateName,list).appendTo('#liContainer');将模板渲染(tmpl)然后插入容器(liContainer)展示即可。第一句将liTemplate标记为一个模板,名称为templateName。第二句利用list将templateName进行渲染,然后插入到liContainer中。list可以使一个数据,也可以是一个对象,例如:var list = {"name":"hello world","name":"heihei"}。总之,tmpl可以让我们不用在写字符串连接,它的可见性太差了,极其难维护。同时,利用tmpl需要三要素:模板,容器,数据。利用数据渲染模板,将结果插入容器中我们便可以轻松完成js中的数据绑定。
事后,我在其官网(https://github.com/jquery/jquery-tmpl)上查阅了相关治疗,发现jquey.tmpl还停留在测试期,并且不再提供升级,被jquery放弃了。。。下一代jquery 模板由JsRender和JsViews承担,相关资料可以去官网上看(JsRender:https://github.com/BorisMoore/jsrender;JsViews:https://github.com/BorisMoore/jsviews)。JsRedner和tmpl差不多,但是据介绍说,JsRender的渲染速度比tmpl快很多很多,到底快多少我也不知道,而且给我的直观感受就是,JsRedner比tmpl的语法简单的写。。这个我喜欢。JsRender强调纯粹的基于字符串的渲染,而且可以不需要dom和jquery的支持,上面我们可以看到tmpl是需要的:$.template("templateName",$('#liTemplate').html());;而JsViews则是建立在JsRender上更高层次的封装,他强调建立交互式的数据驱动视图,具体的貌似我目前还不是很了解。
ok,废话少说,关于JsRender相关的东东在后头我在慢慢整理出来,下面看看它在项目中间的运用,当时我真的大吃一惊,修改View:Views/Person/Ajax代码如下:

//View:Views/Person/Ajax
......
//绑定模板
<script type="text/x-jsrender" id="personListTemplate">
{{for persons}}
<tr>
<td>{{:FirstName}}</td>
<td>{{:LastName}}</td>
<td>
<a href="/Person/Edit/{{:PersonID}}">Edit</a> |
<a href="/Person/Details/{{:PersonID}}">Details</a> |
<a href="/Person/Delete/{{:PersonID}}">Delete</a>
</td>
</tr>
{{/for}}
</script>
//分页模板
<script type="text/x-jsrender" id="pagerTemplate">
{{if HasPreviousPage}}
<a href="#" onclick="getPersonByAjax(1);return false;"><<</a>
<a href="#" onclick="getPersonByAjax({{:PageNumber - 1}});return false;">< Prev</a>
{{else}}
<< < Prev
{{/if}}
{{if HasNextPage}}
<a href="#" onclick="getPersonByAjax({{:PageNumber + 1}});return false;">Next ></a>
<a href="#" onclick="getPersonByAjax({{:PageCount}});return false;">>></a>
{{else}}
Next > >>
{{/if}}
</script> ........ <script type="text/javascript" src="/Scripts/jquery-1.5.1.min.js"></script>
<script type="text/javascript" src="/Scripts/jsrender.js"></script>
<script type="text/javascript">
$(function () {
getPersonByAjax(1);
}); var getPersonByAjax = function (pageNumber) {
$.getJSON("/Person/AjaxJsRenderPage",
{ "page": pageNumber })
.success(function (data) {
$("#personList").empty();
//JsRender渲染、渲染结果(字符串)插入容器
$("#personList").append($("#personListTemplate").render(data));
$("#pager").html($("#pagerTemplate").render(data.pager));
})
.error(function (textStatus) {
alert("msg:" + textStatus.statusText);
})
.complete(function (jqXHQ) {
jqXHQ = null;
});
}
</script>

少去了太多的连接字符串代码(codeless),而且可见性很强,非常容易维护。ok,ajax分页就这么完成了。后头我们在慢慢谈下PagedList的分页思想和整理下JsRender相关的知识。
补充
前面的代码在后来发现了两个问题:
第一、分页时如何定位到具体页?
第二、当数据为空时候的处理?
第二个问题很简单,判断data.persons.length是否为0既可解决,第二个问题要用到window.location.hash。其实就是锚,不过我可以用“window.location.hash = XX”设置标签值和使用“window.location.hash”来获取标签值罢了。下面来看看如何使用location.hash进行分页和页码定位:

$(function () {
getPerson();
});
var getPerson = function () {
var pageNumber;
if (arguments[0] == null) {
var hash = (window.location.hash);
if (hash)
pageNumber = hash.slice(1);
else {
pageNumber = 1;
window.location.hash = pageNumber;
}
}
else {
pageNumber = arguments[0];
window.location.hash = pageNumber;
}
getPersonByAjax(pageNumber);
}

用上面代码替换$(function () {getPersonByAjax(1);});就ok了。可以看到,这里用window.location.hash来获取页面的页码和根据页码来设置window.location.hash,两只始终一致,这样就解决了ajax分页时的具体页定位问题。
ASP.NET MVC利用PagedList分页(二)PagedList+Ajax+JsRender的更多相关文章
- [ASP.NET MVC] 利用动态注入HTML的方式来设计复杂页面
原文:[ASP.NET MVC] 利用动态注入HTML的方式来设计复杂页面 随着最终用户对用户体验需求的不断提高,实际上我们很多情况下已经在按照桌面应用的标准来设计Web应用,甚至很多Web页面本身就 ...
- asp.net mvc easyui datagrid分页
提到 asp.net mvc 中的分页,很多是在用aspnetpager,和easyui datagrid结合的分页却不多,本文介绍的是利用easyui 中默认的分页控件,实现asp.net mvc分 ...
- 转:【译】Asp.net MVC 利用自定义RouteHandler来防止图片盗链
[译]Asp.net MVC 利用自定义RouteHandler来防止图片盗链 你曾经注意过在你服务器请求日志中多了很多对图片资源的请求吗?这可能是有人在他们的网站中盗链了你的图片所致,这会占用你 ...
- Asp.net mvc 知多少(二)
本系列主要翻译自<ASP.NET MVC Interview Questions and Answers >- By Shailendra Chauhan,想看英文原版的可访问http:/ ...
- ASP.NET MVC案例教程(二)
ASP.NET MVC案例教程(二) 让第一个页面跑起来 现在,我们来实现公告系统中的第一个页面——首页.它非常简单,只包括所有公告分类的列表,并且每个列表项是一个超链接.其中分类数据是用我们的Moc ...
- 返璞归真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test
原文:返璞归真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test [索引页] [源码下载] 返璞归真 ...
- ASP.NET MVC利用PagedList分页(一)
前几天看见博客园上有人写ASP.NET MVC的分页思想,这让我不禁想起了PagedList.PagedList是NuGet上提供的一个分页的类库,能对任何IEnumerable<T>进行 ...
- 转:ASP.NET MVC利用TryUpdateModel来做资料更新 (二)
前言 第一篇說明了 TryUpdateModel 的簡單的應用,除了可指定更新的欄位之外也可排除更新特定的欄位,而因為可搭配 Metadata 做欄位驗證為資料又做了一層把關,但在 ASP.NET M ...
- [ASP.NET MVC] 利用自定义的AuthenticationFilter实现Basic认证
很多情况下目标Action方法都要求在一个安全上下文中被执行,这里所谓的安全上下文主要指的是当前请求者是一个经过授权的用户.授权的本质就是让用户在他许可的权限范围内做他能够做的事情,授权的前提是请求者 ...
随机推荐
- zoj 3686 A Simple Tree Problem (线段树)
Solution: 根据树的遍历道的时间给树的节点编号,记录下进入节点和退出节点的时间.这个时间区间覆盖了这个节点的所有子树,可以当做连续的区间利用线段树进行操作. /* 线段树 */ #pragma ...
- 递归查找某个目录下是否存在NOTICE文件
从Catalogs.txt文件中,读取待检查的目录列表.检查这些目录中,是否存在NOTICE文件,如果没有则检查它的父目录,直到cd ..到Repository目录. 如果cd ..到Reposito ...
- js判断是否全是相同的字符串
isSameStr("aa2a") //不都是相同的字符 function isSameStr(str){ var tem=0; for(var i=0;i<str.leng ...
- IE8+等兼容、360调用webkit内核小记
首先是处理IE8.9等的兼容问题,注意以下几点: 1,尽可能严格要求自己使用w3c推荐的方式编写html/css 2,在html页面顶部添加<!DOCHTML html>,不清楚请查看参考 ...
- Java Servlet 回顾
一.转发请求RequestDispatcher 使用request域对象把数据带给转发资源,与重定向的区别:客户端只发出一次请求,服务器端调用多个资源,客户端浏览器地址栏没改变:转发是一次请求,使用的 ...
- c#中创建类(更新中)
类是最常见的一种引用类型,最简单的定义如下 class YouClassNam {} 复杂的类可能包含一下内容 类属性 类属性以及类修饰符. 非嵌套的类修饰符有:public,internal,ab ...
- 织梦DedeCMS网站地图模板
亲和百度蜘蛛,分页多层次特色,织梦系统最好用的网站地图! 用 DedeCMS(织梦) 系统搭建的网站多数都是以优化为主要目标的网站类型,既然是优化站 SEO 手段就离不开为网站设置网站地图.可是 De ...
- Linux grep和find的区别
这是两个不同的命令,关于grep:Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expressi ...
- 韩顺平_JAVA_视频教程_下载(打开迅雷,直接复制链接地址即可下载)
ed2k://|file|韩顺平.循序渐进学.java.从入门到精通.第0讲-开山篇.avi|37021064|f4fb2fb3db938a642146ccc8f0935fed|h=ao2k3ep7p ...
- (转载)delphi实例TDBGrid用右键菜单复制行粘贴行
delphi实例TDBGrid用右键菜单复制行粘贴行 这个从本质上来说就是DBGrid后台数据库的插入 右键复制当前行的相关数据到临时变量点粘贴时,覆盖数据或插入数据! db为数据库: 字段名id,n ...