MVC学习(四)几种分页的实现(3)
在这篇MVC学习(四)几种分页的实现(2)博文中,根据URL中传入的两个参数(页码数,首页、上一页、下一页、末页的标记符)来获得对应的分页数据,
只是传入的参数太多,调用起来不太方便(标记符不能够写错,需要添加新的路由),因此,如果URL只传入页码数就太好,顺着这个思路,有了第三种分页方式。
实现分页形式如下图所示。

下面说说我的思路吧。
为了在试图文件中呈现<input type="text" ...> ,我们需要写上代码@Html.TextBox(Asp.net MVC 3语法),为了呈现Lable,需要写@Html.Label,
这里的@Html,有一个管理它的类 HtmlHelper。为了使用方便,我决定对HtmlHelper类进行扩展。
考虑到有些页面不需要“上一页”,“下一页”之间的“100001”,因此,决定由两种呈现形式,一个是普通的分页,一个是带数字的分页,只有两种分页模式,新建一个枚举类型PageMode,代码如下
/// <summary>
/// 分页模式
/// </summary>
public enum PageMode
{
/// <summary>
/// 普通分页模式
/// </summary>
Normal,
/// <summary>
/// 普通分页加数字分页
/// </summary>
Numeric
}
enum PageMode
面向对象,对象总是很重要的,因此,页面对象是首先需要抽象出来的。
我希望展现的形式是 “总共XX条记录,共XX页,当前第X页 首页 1 2... 上一页 下一页 末页”,想想这段话中,“记录数量”,“共多少页”,“第几页”,还有一条隐形“每页展示数据的大小”,因此,抽象出页面对象PagerInfo(TotalPageCount可以放入这个类中),代码如下。
public class PagerInfo
{
public int RecordCount { get; set; } public int CurrentPageIndex { get; set; } public int PageSize { get; set; }
}
第一步,如何扩展HtmlHelper。
首先,给大家看看微软如何@Html.Label的代码,看下面的截图
在研究了这段代码后,就可以写一个普通的HtmlHelper扩展了,代码如下
public static MvcHtmlString Pager(this HtmlHelper helper, string id, int currentPageIndex, int pageSize, int recordCount, object htmlAttributes, string className, PageMode mode)
{
TagBuilder builder = new TagBuilder("table");
builder.IdAttributeDotReplacement = "_";
builder.GenerateId(id);
builder.AddCssClass(className);
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
return builder.ToMvcHtmlString(TagRenderMode.Normal);
}
"string id"表示这个控件的id号,“int currentPageIndex”表示需要显示第几页数据的页码,
“int pageSize"表示每页显示数据的大小,”object htmlAttributes“表示属性, ”string className“表示样式属性。
看了我的HtmlHepler扩展代码,在与微软的原始代码比较以后,会发现我少了一行重要的代码,就是”tagBuilder.SetInnerText(str);“,即控件在View
的呈现形式。无论是asp.net WebForm页面的服务器控件,还是类似"<input type="text" runat="server">”控件,或者是asp.net MVC的@Html.Label,
他们在页面的都是以字符串的形式展现。
有了这个思路,写出普通的分页形式就比较简单了。
我们只需要给TagBuilder给予正确的字符串就行了。
1、首先获得总的记录数,总页数
总记录数 int pageCount =Convert.ToInt32(Math.Ceiling((double)RecordCount / (double)PageSize));//获得总页数
2、普通分页如何实现
假设我们的url形式为 “http://localhost:11507/Home/FY3?page=2”,那么下一页的url形式便是“http://localhost:11507/Home/FY3?page=3”,因此,我们需要得到传来的绝对路径,不含任何参数。然后根据传来的当前页码数,判断是否有下一页,上一页,并且得到格式化后的url。
这里我先理一理页码数如何传入HtmlHelper中的。
首先,Controller从URL中获取CurrentPageIndex,然后放入PageInfo对象,并且获得分页数据(InfoSource);
然后,我们将InfoSource与PageInfo两个对象放入一个泛型容器PagerQuery<T>,返回给View;
最后,HtmlHelper根据View页面中的对象获得所需参数。
现在回到HtmlHelper的扩展实现。
获得我们需要ULR格式化字符串,如下代码。
var url=new StringBuilder();
url.Append(HttpContext.Current.Request.Url.AbsolutePath+"?page={0}");
我希望展现的形式是 “总共XX条记录,共XX页,当前第X页 首页 上一页 下一页 末页”。现在开始拼字符串。
var sb=new StringBuilder();
sb.Append("<tr><td>");
sb.AppendFormat("总共{0}条记录,共{1}页,当前第{2}页 ",RecordCount,pageCount,currentPageIndex);
//RecordCount,currentPageIndex 值通过PagerInfo传递过来
if(currentPageIndex==1{
sb.Append("<span>首页</span> ";) //如果第一页 不需要给首页真实的链接
}
else{
var url1=string.Format(url.ToString(),1); //格式化URL 得到第一页的url “http://localhost:11507/Home/FY3?page=1”
sb.AppendFormat("<span><a href={0} 首页</a></span> ",url1);
}
如何类推,可得到上一页、下一页、末页的链接。
那么,如果上一页与下一页需要显示数字,怎么办呢? 这里,默认显示10个数字(如果页数不够,就按实际页数显示)
private static string GetNumericPage(int currentPageIndex, int pageSize, int recordCount, int pageCount, string url)
{
var k = currentPageIndex / ;
var m = currentPageIndex % ; var sb = new StringBuilder();
if (currentPageIndex / == pageCount / )//10个号码 为一组
{
if (m == )
{
k--;
m = ;
}
else
m = pageCount % ;
}
else
m = ; for (var i = k * + ; i <= k * + m; i++)//如果是第1页 则 1...10 第11页,则11...20
//for(int i=currentPageIndex;i<LastPage;i++)
{
if (i == currentPageIndex) sb.AppendFormat("<span><font color=red><b>{0}</b></font></span> ", i);
else
{
var url1 = string.Format(url, i);
sb.AppendFormat("<span><a href={0}>{1}</a></span> ", url1, i);
}
} return sb.ToString();
}
}
string GetNumericPage
现在,可以得到扩展标签代码,如下
public static MvcHtmlString Pager(this HtmlHelper helper, string id, int currentPageIndex, int pageSize, int recordCount, object htmlAttributes, string className, PageMode mode)
{
TagBuilder builder = new TagBuilder("table");
builder.IdAttributeDotReplacement = "_";
builder.GenerateId(id);
builder.AddCssClass(className);
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
builder.InnerHtml = GetNormalPage(currentPageIndex, pageSize, recordCount, mode); return builder.ToMvcHtmlString(TagRenderMode.Normal); } static MvcHtmlString ToMvcHtmlString(this TagBuilder tagBuilder, TagRenderMode renderMode)
{
return new MvcHtmlString(tagBuilder.ToString(renderMode));
}
得到分页字符串代码了,如下
private static string GetNormalPage(int currentPageIndex, int PageSize, int RecordCount, PageMode mode)
{ int pageCount =Convert.ToInt32(Math.Ceiling((double)RecordCount / (double)PageSize));//获得总页数
var url = new StringBuilder();
url.Append(HttpContext.Current.Request.Url.AbsolutePath + "?page={0}"); var sb = new StringBuilder();
sb.Append("<tr><td>");
sb.AppendFormat("总共{0}条记录,共{1}页,当前第{2}页 ", RecordCount, pageCount, currentPageIndex);
if (currentPageIndex == )
sb.Append("<span>首页</span> ");
else
{
var url1 = string.Format(url.ToString(), );
sb.AppendFormat("<span><a href={0}>首页</a></span> ", url1);
}
if (currentPageIndex > )
{
var url1 = string.Format(url.ToString(), currentPageIndex - );
sb.AppendFormat("<span><a href={0}>上一页</a></span> ", url1);
}
else
sb.Append("<span>上一页</span> ");
if (mode == PageMode.Numeric)
sb.Append(GetNumericPage(currentPageIndex, PageSize, RecordCount, pageCount, url.ToString()));
if (currentPageIndex < pageCount)
{
string url1 = string.Format(url.ToString(), currentPageIndex + );
sb.AppendFormat("<span><a href={0}>下一页</a></span> ", url1);
}
else
sb.Append("<span>下一页</span> "); if (currentPageIndex == pageCount)
sb.Append("<span>末页</span> ");
else
{
string url1 = string.Format(url.ToString(), pageCount);
sb.AppendFormat("<span><a href={0}>末页</a></span> ", url1);
}
return sb.ToString();
}
GetNormalPage(int currentPageIndex, int PageSize, int RecordCount, PageMode mode)
那么,承载数据的容器时什么呢,因为Model是会随时变化的(泛型类最佳实现),代码如下
public class PagerQuery<T> : List<T>
{
public PagerQuery(PagerInfo pager, IEnumerable<T> source)
{
this.Pager = pager;
int BeforePageIndex = pager.CurrentPageIndex - ;
if (BeforePageIndex < )
{
BeforePageIndex = ;
}
var entityList = source.Skip((BeforePageIndex) * pager.PageSize).Take(pager.PageSize);
AddRange(entityList);
}
public PagerInfo Pager { get; set; }
}
Controller代码如下
public ActionResult FY2(int? page)
{
LZSEntities _lzsDb=new LZSEntities();
PagerInfo pager = new PagerInfo();
pager.RecordCount = _lzsDb.MyTestPages.Count();
pager.PageSize = ;
if (page == null)
{
pager.CurrentPageIndex = ;
}
else
{
pager.CurrentPageIndex = Convert.ToInt32(page);
} var result = _lzsDb.MyTestPages; IEnumerable<MyTestPages> info2 = result;
var query = new PagerQuery<MyTestPages>(pager, info2);
return View(query);
}
public ActionResult FY2(int? page)
View代码如下
@model MVCFY2.PageHelpers.PagerQuery<MVCFY2.Models.MyTestPages>
@using MVCFY2.Models
@using MVCFY2.PageHelpers;
@{
Layout = null;
} <!DOCTYPE html> <html>
<head>
<title>FY3</title>
</head>
<body>
@* ReSharper disable once Html.Obsolete *@
<table cellpadding="" cellspacing="" height="200px" width="300px" bordercolor="blue">
<tr> <th height="30px">
序号
</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td align="center" height="30px">
@item.Id
</td>
</tr>
} </table>
<div> <p> @Html.Pager("pager1", Model.Pager.CurrentPageIndex, Model.Pager.PageSize, Model.Pager.RecordCount, PageMode.Numeric)</p>
</div>
</body>
</html>
View
VS 2010 MVC3,配置好数据库后,运行即可,源代码点此下载。
我感觉,第三种分页形式是很完美的,只是重复从第一页跳到最后一页再最后一页跳至第一页,分页缓慢,查看资源管理器,内存被占了很多,未曾释放,因此,
希望各位可以告诉我高效的改进方法~~~
MVC学习(四)几种分页的实现(3)的更多相关文章
- MVC学习四:Razor视图语法
@{ Layout = null; } <hr /> <!DOCTYPE html> @this.GetType().Assembly.Location.ToString() ...
- MVC学习四
第七节 讲述了增加model中类的属性,由于数据库中已存在表,表中没有存在新加的列,所以可以删除数据库或者在数据库中新增一列,另可以在controller中新增一个数据库初始化的类,并在Globa ...
- spring MVC 学习(四)---拦截器,视图解析器
1.接口HandlerInterceptor 该接口包含3个方法,分别是preHandle,postHandle,afterCompletion,分别代表着执行前,执行后,执行完成要执行的方法,其中p ...
- MVC学习(四)几种分页的实现(2)
在第一种分页方式中,仅仅实现了分页,但并未有体现出MVC的优势,没有体现出泛型编程思想,尤其在数据量很大的时候,分页十分缓慢,除此之外,还没有实现很好的封装,不是一个通用方法. 因此,我希望只要传入数 ...
- sqlserver的四种分页方式
第一种:ROW_NUMBER() OVER()方式 select * from ( select *, ROW_NUMBER() OVER(Order by ArtistId ) AS RowId f ...
- asp.net mvc 的几种分页Pager
第一种 /// <summary> /// 分页Pager显示 /// </summary> /// <param name="html">&l ...
- ASP.NET MVC中有四种过滤器类型
在ASP.NET MVC中有四种过滤器类型
- .NET MVC 学习笔记(四)— 基于Bootstarp自定义弹出框
.NET MVC 学习笔记(四)—— 基于Bootstarp自定义弹出框 转载自:https://www.cnblogs.com/nele/p/5327380.html (function ($) { ...
- Java开发学习(四十一)----MyBatisPlus标准数据层(增删查改分页)开发
一.标准CRUD使用 对于标准的CRUD功能都有哪些以及MyBatisPlus都提供了哪些方法可以使用呢? 我们先来看张图: 1.1 环境准备 这里用的环境就是Java开发学习(四十)----MyBa ...
随机推荐
- Whats meaning of “EXPORT_SYMBOL” in Linux kernel code?
EXPORT_SYMBOL的作用是什么? EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一 ...
- bzoj4130: [PA2011]Kangaroos
Description 定义两个区间互相匹配表示这两个区间有交集. 给出长度为N的区间序列A,M次询问,每次询问序列A中最长的连续子序列,使得子序列中的每个区间都与[L,R]互相匹配 N<=50 ...
- Mysql 自定义HASH索引带来的巨大性能提升----[真相篇]
推倒重来 俗话说no zuo no die why you try,这时候我又忍不住zuo了,吭哧吭哧的把解决过程发上博客,向全世界宣布,哥又搞定个难题. 剧情的发展往往是看起来主角完全掌握了局势的情 ...
- 学习SQL的点点滴滴(三)-修改数据库的兼容级别
语法 ALTER DATABASE database_name SET COMPATIBILITY_LEVEL = { 80 | 90 | 100 } 参数 database_name 要修改的数据库 ...
- Datagridview 列绑定
Datagridview 列绑定 dataGridView1.Columns.Clear(); dataGridView1.Columns.Add("id", "id&q ...
- 本地和VMware虚拟主机之间的网络访问
在需要设置的虚拟主机节点上右键,点击[设置...] 在打开的虚拟机设置中,选中[网络适配器],之后在右边设置网络连接为[自定义:指定的虚拟网络] 然后设置同一网关即可.
- loadView、viewDidLoad、initWithCoder、initWithNibName、awakeFromNib的用法
转载,原地址为:http://jianyu996.blog.163.com/blog/static/11211455520131226840879/ 请尊重原创: 1,无论XIB还是代码创建都会调用l ...
- Windows下运行python脚本报错“ImportError: No Module named ...”的解决方法
之前遇到一个问题,在Pycharm或IPython之类的IDE上运行脚本正常,但是直接运行或cmd命令行运行的时候报了模块未能找到的错误--ImportError: No Module named . ...
- Spring mvc 配置详解
现在主流的Web MVC框架除了Struts这个主力 外,其次就是Spring MVC了,因此这也是作为一名程序员需要掌握的主流框架,框架选择多了,应对多变的需求和业务时,可实行的方案自然就多了.不过 ...
- django(五)
URLs 当一个用户请求一个页面时,Django将按照顺序去匹配每一个模式,并停在第一个匹配请求的URL上. 如果你的url多个正则表达式都能匹配上咋弄?小心出错,这个是按照顺序匹配的 url(r'^ ...