最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

Asp.Net MVC 分页、检索、排序整体实现代码

来源:动视网 责编:小采 时间:2020-11-27 22:36:08
文档

Asp.Net MVC 分页、检索、排序整体实现代码

Asp.Net MVC 分页、检索、排序整体实现代码:很多时候需要这样的功能,对表格进行分页、排序和检索。这个有很多实现的方式,有现成的表格控件、用前端的mvvm,用户控件。但很多时候看着很漂亮的东西你想进一步控制的时候却不那么如意。这里自己实现一次,功能不是高大全,但求一个清楚明白,也欢迎园友拍
推荐度:
导读Asp.Net MVC 分页、检索、排序整体实现代码:很多时候需要这样的功能,对表格进行分页、排序和检索。这个有很多实现的方式,有现成的表格控件、用前端的mvvm,用户控件。但很多时候看着很漂亮的东西你想进一步控制的时候却不那么如意。这里自己实现一次,功能不是高大全,但求一个清楚明白,也欢迎园友拍


很多时候需要这样的功能,对表格进行分页、排序和检索。这个有很多实现的方式,有现成的表格控件、用前端的mvvm,用户控件。但很多时候看着很漂亮的东西你想进一步控制的时候却不那么如意。这里自己实现一次,功能不是高大全,但求一个清楚明白,也欢迎园友拍砖。前端是bootstrap3+jPaginate,后台基于membership。没什么难点。

先上效果图。

分页其实就是处理好 每页项目数、总项目数、总页数、当前页。为了方便复用,就先从仓库开始说起。

一、建立仓库

  1.定义Ipager接口,需要分页的模型仓库继承这个接口

namespace Protal.Model.Abstract
{
 /// <summary>
 /// 分页处理
 /// </summary>
 public interface IPager
 {
 /// <summary>
 /// 每页项目数
 /// </summary>
 /// <value>The page item count.</value>
 int PageItemCount { get; set; }
 /// <summary>
 /// 总页数
 /// </summary>
 /// <value>The totoal page.</value>
 int TotoalPage { get; }
 /// <summary>
 /// 显示的页数
 /// </summary>
 /// <value>The display page.</value>
 int DisplayPage { get; set; }
 /// <summary>
 /// 满足条件的总数目
 /// </summary>
 int TotalItem { get; set; }
 }
}

2.定义IUsersRepository,主要处理User 相关的业务逻辑。Find函数是主要的查询方法,order表示顺反排序。

 public interface IUsersRepository : IPager
 {
 /// <summary>
 /// Post list
 /// </summary>
 /// <param name="order">Order expression</param>
 /// <param name="filter">Filter expression</param>
 /// <param name="skip">Records to skip</param>
 /// <param name="take">Records to take</param>
 /// <returns>List of users</returns>
 IEnumerable<User> Find(int order=0,string filter="", int skip = 0, int take = 10);
 /// <summary>
 /// Get single post
 /// </summary>
 /// <param name="name">User id</param>
 /// <returns>User object</returns>
 User FindByName(string name);
 /// <summary>
 /// Add new user
 /// </summary>
 /// <param name="user">Blog user</param>
 /// <returns>Saved user</returns>
 User Add(User user);
 /// <summary>
 /// Update user
 /// </summary>
 /// <param name="user">User to update</param>
 /// <returns>True on success</returns>
 bool Update(User user);
 /// <summary>
 /// Save user profile
 /// </summary>
 /// <param name="user">Blog user</param>
 /// <returns>True on success</returns>
 bool SaveProfile(User user);
 /// <summary>
 /// Delete user
 /// </summary>
 /// <param name="userName">User ID</param>
 /// <returns>True on success</returns>
 bool Remove(string userName);
 }

二、仓库的实现和绑定

  主要方法:Membership的中的User和我们自定义的不一样,所以存在一个转换

 public class UsersRepository : IUsersRepository
 {
 /// <summary>
 /// The _user list
 /// </summary>
 private List<User> _userList = new List<User>();
 /// <summary>
 /// The _page item count
 /// </summary>
 private int _pageItemCount;
 /// <summary>
 /// The _display page
 /// </summary>
 private int _displayPage;
 /// <summary>
 /// The _usercount
 /// </summary>
 private int _usercount;
 /// <summary>
 /// The _total item
 /// </summary>
 private int _totalItem;
 /// <summary>
 /// 标记是否有查询条件 没有的话则返回全部数目
 /// </summary>
 private Func<User, bool> _func;

 /// <summary>
 /// Gets or sets the users.
 /// </summary>
 /// <value>The users.</value>
 public List<User> Users
 {
 get
 {
 int count;
 var usercollection = Membership.GetAllUsers(0, 999, out count);
 if (count == _usercount) return _userList;
 _usercount = count;
 var members = usercollection.Cast<MembershipUser>().ToList();
 foreach (var membershipUser in members)//这里存在一个转换
 {
 _userList.Add(new User
 {
 Email = membershipUser.Email,
 UserName = membershipUser.UserName,
 //roles password
 });
 }
 return _userList;
 }
 set { _userList = value; }
 } 
//查询
public IEnumerable<User> Find(int order = 0, string filter = "", int skip = 0, int take = 10)
 {
 if (take == 0) take = Users.Count;
 //过滤
 _func = string.IsNullOrEmpty(filter) ? (Func<User, bool>) (n => n.UserName != "") : (n => n.UserName.Contains(filter));
 var users = Users.Where(_func).ToList();
 //更新总数目
 _totalItem = users.Count;
 users = order == 0 ? users.OrderBy(n => n.UserName).ToList() : users.OrderByDescending(n => n.UserName).ToList();
 return users.Skip(skip).Take(take);
 }
 /// <summary>
 /// 每页项目数
 /// </summary>
 /// <value>The page item count.</value>
 public int PageItemCount
 {
 get
 {
 if (_pageItemCount == 0)
 {
 _pageItemCount = ProtalConfig.UserPageItemCount;
 }
 return _pageItemCount;
 }
 set { _pageItemCount = value; }
 }

 /// <summary>
 /// 总页数
 /// </summary>
 /// <value>The totoal page.</value>
 public int TotoalPage
 {
 get
 {
 var page = (int) Math.Ceiling((double) TotalItem/PageItemCount);
 return page==0?1:page; 
 }
 }
 /// <summary>
 /// 显示的页数
 /// </summary>
 /// <value>The display page.</value>
 public int DisplayPage
 {
 get
 {
 if (_displayPage == 0)
 {
 _displayPage = ProtalConfig.UserDisplayPage;
 }
 return _displayPage;
 }
 set { _displayPage = value; }
 }


 /// <summary>
 /// 满足条件的总数目 保持更新
 /// </summary>
 /// <value>The total item.</value>
 public int TotalItem
 {
 get
 {
 if (_func == null)
 _totalItem = Users.Count;
 return _totalItem;
 }
 set { _totalItem = value; }
 }
}

ProtalConfig.UserDisplayPage 这里是通过配置实现一个默认页数,让用户可以再webconfig中更改行列的数目。

public static int UserPageItemCount
 {
 get
 {
 if (_userPageItemCount == 0)
 {
 _userPageItemCount = WebConfigurationManager.AppSettings["UserPageItemCount"] != null ?
 Convert.ToInt16(WebConfigurationManager.AppSettings["UserPageItemCount"]) : 5;
 }
 return _userPageItemCount;
 }
 set
 {
 _userPageItemCount = value;
 }
 }

再进行绑定:

 _kernel.Bind<IUsersRepository>().To<UsersRepository>(); 

三、控制器部分

我们需要两个页面,一个主页面Index,一个负责局部刷新的部分视图 UserTable

下面是主要的方法,主要逻辑都在在仓库中处理了。

 [Authorize]
 public class UserManagerController : Controller
 {
 /// <summary>
 /// The _repository
 /// </summary>
 private readonly IUsersRepository _repository;

 /// <summary>
 /// Initializes a new instance of the <see cref="UserManagerController"/> class.
 /// </summary>
 /// <param name="iRepository">The i repository.</param>
 public UserManagerController(IUsersRepository iRepository)
 {
 _repository = iRepository; 
 }

 /// <summary>
 /// Indexes the specified page index.
 /// </summary>
 /// <param name="pageIndex">Index of the page.</param>
 /// <returns>ActionResult.</returns>
 public ActionResult Index(int pageIndex=1)
 {
 ViewBag.DisplayPage = _repository.DisplayPage;
 pageIndex = HandlePageindex(pageIndex);
 
 //支持地址栏直接分页
 ViewBag.CurrentPage = pageIndex;
 return View();
 }


 /// <summary>
 /// Users table. 分页模块
 /// </summary>
 /// <param name="pageIndex">Index of the page.</param>
 /// <param name="order">The order.</param>
 /// <param name="filter">The filter str.</param>
 /// <returns>ActionResult.</returns>
 public ActionResult UserTable(int pageIndex = 1, int order = 0, string filter = "")
 {
 pageIndex = HandlePageindex(pageIndex);
 var skip = (pageIndex - 1) * _repository.PageItemCount;
 var users = _repository.Find(order,filter, skip, _repository.PageItemCount);
 
 //总用户数
 ViewBag.TotalUser = _repository.TotalItem;
 //总页数
 ViewBag.TotalPageCount = _repository.TotoalPage; ;

 return PartialView(users);
 }

 /// <summary>
 /// 处理页数 防止过大或过小
 /// </summary>
 /// <param name="index"></param>
 /// <returns></returns>
 private int HandlePageindex(int index)
 {
 var totoalpage = _repository.TotoalPage;
 if (index == 0) return 1;
 return index > totoalpage ? totoalpage : index;
 }
}

四、视图部分Html jquery

 1.Index.cshtml

<script src="~/Scripts/form.js"></script>
<div class="container">
 <h4 class="bottomline">管理用户</h4>
 <p>
 <button data-target="#adduser" id="adduserbt" data-toggle="modal" class="btn btn-info btn-hover">新增用户</button>
 <button class="btn btn-danger" id="deluser">删除</button>
 <span class="errorinfo"></span>
 <input type="search" class="pull-right" id="usersearch" placeholder="搜索"/>
 </p>
 <div id="userpart">
 @Html.Action("UserTable",new{pageIndex=ViewBag.CurrentPage})
 </div>
 <div id="userpager"></div>
 <input type="hidden" id="dispalypage" value="@ViewBag.DisplayPage"/>
 <input type="hidden" id="page" value="@ViewBag.CurrentPage"/>
 <input type="hidden" id="currentpage" value="@ViewBag.CurrentPage"/>

</div>
<div class="modal fade adduserbox"id="adduser" tabindex="1" role="dialog" aria-hidden="true">
 <div class="modal-content">
 <div class="modal-header">
 <button type="button" class="close" data-dismiss="modal" aria-hidden="true" >×</button>
 <h4 class="modal-title">Add new User</h4>
 </div>
 <div class="modal-body">
 @{
 Html.RenderAction("Create","UserManager");
 }
 </div>
 </div>
</div>

@section Scripts {
 @Scripts.Render("~/bundles/jqueryval")
}

2.UserTable.cshtml,角色部分还未处理,这个表格更新之后,也会更新满足条件的用户数和新的总页数,触发Jpaginate重新分页一次。

@model IEnumerable<Protal.Model.Data.User.User>
 <table id="usertable" class="table table-striped table-condensed table-hover table-bordered">
 <tr>
 <th><input type="checkbox" id="allcheck" /><label for="allcheck">全选</label></th>
 <th><a href="#" id="usersort" data-order="0" class="glyphicon-sort">名称</a></th>
 <th>角色</th>
 <th>E-mail</th>
 </tr>
 <tbody>
 @foreach (var item in Model) {
 <tr>
 <td> <input type="checkbox" data-id="@item.UserName" /></td>
 <td> <a>@item.UserName</a> </td>
 <td> @Html.Raw(item.Role) </td>
 <td> @item.Email</td>
 </tr>
 }</tbody>
 <tfoot>
 <tr>
 <td colspan="4">
 <span>@Html.Raw("共"+ViewBag.TotalUser+"人")</span> @*<span>@ViewBag.TotalPageCount</span>*@
 </td>
 </tr>
 </tfoot>
 </table>
 <input type="hidden" id="totoalpage" value="@ViewBag.TotalPageCount"/>

3.脚本

其中用到的像checkall,infoShow 都是自己扩展的一些简单的方法,用于全选和提示。

$(function () {

 var options = {
 dataType: 'json',
 success: processJson
 };
 pageagin($("#totoalpage").val());
 //分页
 function pageagin(totalcount) {
 $("#userpager").paginate({
 count: totalcount,
 start: $("#page").val(),
 dispaly: $("#dispalypage").val(),
 boder: false,
 border_color: '#fff',//自己调整样式。
 text_color: 'black',
 background_color: 'none',
 border_hover_color: '#ccc',
 text_hover_color: '#000',
 background_hover_color: '#fff',
 images: false,
 mouse: 'press',
 onChange: function (page) { //翻页
 paging(page);
 $("#currentpage").val(page);
 }
 });
 }
 //分页更新
 function paging(page) {
 $.post("/Users/UserTable", { pageIndex: page, order: $("#userpart").attr("data-order"), filter: $.trim($("#usersearch").val()) }, function (data) {
 $("#userpart").html(data);
 });
 }

 //排序
 $("#usersort").live("click",function () {
 $("#userpart").triggerdataOrder();
 paging( $("#currentpage").val());
 });
 
 //搜索
 $("#usersearch").keyup(function() {
 paging($("#currentpage").val());
 pageagin($("#totoalpage").val());
 });

 //处理form
 $("#userForm").submit(function () {
 $(this).ajaxSubmit(options);
 return false;
 });
 function processJson(data) {
 if (data == 1) {
 location.reload();
 } else {
 alert("添加失败");
 }
 }

 //高亮
 $("#unav li:eq(0)").addClass("active");
 $("#adnav li:eq(2)").addClass("active");
 //全选/全不选
 $("#allcheck").checkall($("#usertable tbody input[type='checkbox']"));

 //删除用户
 $("#deluser").click(function () {
 var checks = $("#usertable tbody input[type='checkbox']:checked");
 var lens = checks.length;
 if (lens == 0) {
 $.infoShow("未选择删除对象",0);
 return false;
 }
 if (confirm("确定要删除所选中用户?")) {
 for (var i = 0; i < lens; i++) {
 var $chek = checks.eq(i);
 var id = $chek.attr("data-id");
 var tr = $chek.parent().parent();
 $.post("Users/DeleteUser", { id: id }, function (data) {
 if (data == 1) {
 tr.fadeOut();
 $.infoShow("删除成功", 1);
 } else {
 $.infoShow("删除失败", 0);
 }
 });
 }
 }
 return true;
 });
 
 // 增加用户
 $("#adduserbt").click(function() {
 $(".modal-header").show();
 });
 })

到这里就是全部的代码,供大家和自己参考。

再给大家看两个效果图,一个是kendoui的grid,一个是Angular做的分页。后面有机会给大家介绍。

Kendo- Grid

Kendo和MVC框架融合度比较高,它的核心代码如下:

@model IEnumerable<Kendo.Mvc.Examples.Models.ProductViewModel>

@(Html.Kendo().Grid(Model)
 .Name("Grid")
 .Columns(columns =>
 {
 columns.Bound(p => p.ProductID).Groupable(false);
 columns.Bound(p => p.ProductName);
 columns.Bound(p => p.UnitPrice);
 columns.Bound(p => p.UnitsInStock);
 })
 .Pageable()
 .Sortable()
 .Scrollable() 
 .Filterable() 
 .DataSource(dataSource => dataSource 
 .Ajax()
 .ServerOperation(false) 
 )
)

AngularJs 核心还是调用封装好的API函数,相当于上面的仓库中的方法,然后通过模型绑定。

总结一下:自己实现代码量比较多,功能不全,有重复造轮子的感觉,但可以较好的控制,基本够用;kendo的方式感觉高大全,用熟了开发速度快。就是多一些引用,且需要担心kendoui和其他的ui框架会有冲突。前端MVVM的方式我了解还不够深,感觉前端脚本的代码量也蛮多,效果不错。但生成的html代码很少。上面这个表格。chrome F12或者右键查看源码都是下面这样子的:

主要的就一个div 

 <div data-ng-app="blogAdmin" data-ng-view="" id="ng-view"></div>

自我保护倒是蛮好,也就是SEO可能有问题。应该还有更好的方式,猿友们指点指点。

<html>
<head>
 <title>Name of the blog (Admin)</title>
 <link rel="shortcut icon" href="/pics/blogengine.ico" type="image/x-icon" />
 <meta charset="utf-8" />
 <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
 <meta name="apple-mobile-web-app-capable" content="yes" />
 <meta name="apple-mobile-web-app-status-bar-style" content="black" />
 <meta name="format-detection" content="telephone=no" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
 <link href="/Content/bootstrap/bootstrap.css" rel="stylesheet"/>
<link href="/Content/bootstrap/bootstrap-theme.css" rel="stylesheet"/>
<link href="/Content/toastr.css" rel="stylesheet"/>
<link href="/Content/font-awesome.css" rel="stylesheet"/>
<link href="/Content/editor.css" rel="stylesheet"/>
<link href="/Content/app.css" rel="stylesheet"/>

 <script type="text/javascript">
 if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
 var msViewportStyle = document.createElement("style");
 var mq = "@-ms-viewport{width:auto!important}";
 msViewportStyle.appendChild(document.createTextNode(mq));
 document.getElementsByTagName("head")[0].appendChild(msViewportStyle);
 }
 </script>
</head>
<body>
 <script type="text/javascript">
 var SiteVars = {
 ApplicationRelativeWebRoot: '/',
 RelativeWebRoot: '/',
 BlogInstanceId: '96d5b379-7e1d-4dac-a6ba-1e50db561b04',
 UserName: 'admin',
 UserRights: ['ViewDetailedErrorMessages', 'AccessAdminPages', 'AccessAdminSettingsPages', 'ManageWidgets', 'ViewPublicComments', 'ViewUnmoderatedComments', 'CreateComments', 'ModerateComments', 'ViewPublicPosts', 'ViewUnpublishedPosts', 'CreateNewPosts', 'EditOwnPosts', 'EditOtherUsersPosts', 'DeleteOwnPosts', 'DeleteOtherUsersPosts', 'PublishOwnPosts', 'PublishOtherUsersPosts', 'ViewPublicPages', 'ViewUnpublishedPages', 'CreateNewPages', 'EditOwnPages', 'ViewRatingsOnPosts', 'SubmitRatingsOnPosts', 'ViewRoles', 'CreateNewRoles', 'EditRoles', 'DeleteRoles', 'EditOwnRoles', 'EditOtherUsersRoles', 'CreateNewUsers', 'DeleteUserSelf', 'DeleteUsersOtherThanSelf', 'EditOwnUser', 'EditOtherUsers'],
 AbsoluteWebRoot: 'http://localhost:53265/',
 Version: 'BlogEngine.NET ' + '2.9.1.0',
 IsPrimary: 'True',
 IsAdmin: 'True',
 AppRoot: function (url) { window.location = '/' + url; return false; },
 BlogRoot: function (url) { window.location = '/' + url; }
 };
 </script>
 <script type="text/javascript" src="admin.res.axd"></script>
 <div id="container" class="app-wrapper ltr">
 <div data-ng-app="blogAdmin" data-ng-view="" id="ng-view"></div>
 </div>
 
 <script src="https://www.gxlcms.com/scripts/jquery-2.0.3.js"></script>
<script src="https://www.gxlcms.com/scripts/jquery.validate.js"></script>
<script src="https://www.gxlcms.com/scripts/jquery.form.js"></script>
<script src="https://www.gxlcms.com/scripts/toastr.js"></script>
<script src="https://www.gxlcms.com/Scripts/angular.min.js"></script>
<script src="https://www.gxlcms.com/Scripts/angular-route.min.js"></script>
<script src="https://www.gxlcms.com/Scripts/angular-animate.min.js"></script>
<script src="https://www.gxlcms.com/Scripts/angular-sanitize.min.js"></script>
<script src="https://www.gxlcms.com/admin/be-grid.js"></script>
<script src="https://www.gxlcms.com/admin/app.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/dashboard.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/blogs.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/posts.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/pages.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/tags.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/categories.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/comments.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/users.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/roles.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/profile.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/settings.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/packages.js"></script>
<script src="https://www.gxlcms.com/admin/controllers/common.js"></script>
<script src="https://www.gxlcms.com/admin/services.js"></script>
<script src="https://www.gxlcms.com/scripts/bootstrap.js"></script>
<script src="https://www.gxlcms.com/scripts/moment.js"></script>

</body>
</html>

PS:这个东西没什么难度,逻辑都在仓库中,要源码的同学我后续分离出来了再贴出来。当然这个又很多方式,我也不是要秀什么框架,但我目前项目的需求是要这么分开的。一个控制器是可用解决所有问题,但我其他模型也要分页又要便于测试难道我都写在控制器中吗?

Demo 下载请戳这里

文档

Asp.Net MVC 分页、检索、排序整体实现代码

Asp.Net MVC 分页、检索、排序整体实现代码:很多时候需要这样的功能,对表格进行分页、排序和检索。这个有很多实现的方式,有现成的表格控件、用前端的mvvm,用户控件。但很多时候看着很漂亮的东西你想进一步控制的时候却不那么如意。这里自己实现一次,功能不是高大全,但求一个清楚明白,也欢迎园友拍
推荐度:
标签: 实现 排序 net
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top