Asp.Net MVC 分頁、檢索、排序整體實(shí)現(xiàn)代碼
很多時候需要這樣的功能,對表格進(jìn)行分頁、排序和檢索。這個有很多實(shí)現(xiàn)的方式,有現(xiàn)成的表格控件、用前端的mvvm,用戶控件。但很多時候看著很漂亮的東西你想進(jìn)一步控制的時候卻不那么如意。這里自己實(shí)現(xiàn)一次,功能不是高大全,但求一個清楚明白,也歡迎園友拍磚。前端是bootstrap3+jPaginate,后臺基于membership。沒什么難點(diǎn)。
先上效果圖。

分頁其實(shí)就是處理好 每頁項目數(shù)、總項目數(shù)、總頁數(shù)、當(dāng)前頁。為了方便復(fù)用,就先從倉庫開始說起。
一、建立倉庫
1.定義Ipager接口,需要分頁的模型倉庫繼承這個接口
namespace Protal.Model.Abstract
{
/// <summary>
/// 分頁處理
/// </summary>
public interface IPager
{
/// <summary>
/// 每頁項目數(shù)
/// </summary>
/// <value>The page item count.</value>
int PageItemCount { get; set; }
/// <summary>
/// 總頁數(shù)
/// </summary>
/// <value>The totoal page.</value>
int TotoalPage { get; }
/// <summary>
/// 顯示的頁數(shù)
/// </summary>
/// <value>The display page.</value>
int DisplayPage { get; set; }
/// <summary>
/// 滿足條件的總數(shù)目
/// </summary>
int TotalItem { get; set; }
}
}
2.定義IUsersRepository,主要處理User 相關(guān)的業(yè)務(wù)邏輯。Find函數(shù)是主要的查詢方法,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);
}
二、倉庫的實(shí)現(xiàn)和綁定
主要方法:Membership的中的User和我們自定義的不一樣,所以存在一個轉(zhuǎn)換
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>
/// 標(biāo)記是否有查詢條件 沒有的話則返回全部數(shù)目
/// </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)//這里存在一個轉(zhuǎn)換
{
_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();
//更新總數(shù)目
_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>
/// 每頁項目數(shù)
/// </summary>
/// <value>The page item count.</value>
public int PageItemCount
{
get
{
if (_pageItemCount == 0)
{
_pageItemCount = ProtalConfig.UserPageItemCount;
}
return _pageItemCount;
}
set { _pageItemCount = value; }
}
/// <summary>
/// 總頁數(shù)
/// </summary>
/// <value>The totoal page.</value>
public int TotoalPage
{
get
{
var page = (int) Math.Ceiling((double) TotalItem/PageItemCount);
return page==0?1:page;
}
}
/// <summary>
/// 顯示的頁數(shù)
/// </summary>
/// <value>The display page.</value>
public int DisplayPage
{
get
{
if (_displayPage == 0)
{
_displayPage = ProtalConfig.UserDisplayPage;
}
return _displayPage;
}
set { _displayPage = value; }
}
/// <summary>
/// 滿足條件的總數(shù)目 保持更新
/// </summary>
/// <value>The total item.</value>
public int TotalItem
{
get
{
if (_func == null)
_totalItem = Users.Count;
return _totalItem;
}
set { _totalItem = value; }
}
}
ProtalConfig.UserDisplayPage 這里是通過配置實(shí)現(xiàn)一個默認(rèn)頁數(shù),讓用戶可以再webconfig中更改行列的數(shù)目。
public static int UserPageItemCount
{
get
{
if (_userPageItemCount == 0)
{
_userPageItemCount = WebConfigurationManager.AppSettings["UserPageItemCount"] != null ?
Convert.ToInt16(WebConfigurationManager.AppSettings["UserPageItemCount"]) : 5;
}
return _userPageItemCount;
}
set
{
_userPageItemCount = value;
}
}
再進(jìn)行綁定:
_kernel.Bind<IUsersRepository>().To<UsersRepository>();
三、控制器部分
我們需要兩個頁面,一個主頁面Index,一個負(fù)責(zé)局部刷新的部分視圖 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);
//總用戶數(shù)
ViewBag.TotalUser = _repository.TotalItem;
//總頁數(shù)
ViewBag.TotalPageCount = _repository.TotoalPage; ;
return PartialView(users);
}
/// <summary>
/// 處理頁數(shù) 防止過大或過小
/// </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,角色部分還未處理,這個表格更新之后,也會更新滿足條件的用戶數(shù)和新的總頁數(shù),觸發(fā)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 都是自己擴(kuò)展的一些簡單的方法,用于全選和提示。
$(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',//自己調(diào)整樣式。
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做的分頁。后面有機(jī)會給大家介紹。
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 核心還是調(diào)用封裝好的API函數(shù),相當(dāng)于上面的倉庫中的方法,然后通過模型綁定。

總結(jié)一下:自己實(shí)現(xiàn)代碼量比較多,功能不全,有重復(fù)造輪子的感覺,但可以較好的控制,基本夠用;kendo的方式感覺高大全,用熟了開發(fā)速度快。就是多一些引用,且需要擔(dān)心kendoui和其他的ui框架會有沖突。前端MVVM的方式我了解還不夠深,感覺前端腳本的代碼量也蠻多,效果不錯。但生成的html代碼很少。上面這個表格。chrome F12或者右鍵查看源碼都是下面這樣子的:
主要的就一個div
<div data-ng-app="blogAdmin" data-ng-view="" id="ng-view"></div>
自我保護(hù)倒是蠻好,也就是SEO可能有問題。應(yīng)該還有更好的方式,猿友們指點(diǎn)指點(diǎn)。
<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="/scripts/jquery-2.0.3.js"></script>
<script src="/scripts/jquery.validate.js"></script>
<script src="/scripts/jquery.form.js"></script>
<script src="/scripts/toastr.js"></script>
<script src="/Scripts/angular.min.js"></script>
<script src="/Scripts/angular-route.min.js"></script>
<script src="/Scripts/angular-animate.min.js"></script>
<script src="/Scripts/angular-sanitize.min.js"></script>
<script src="/admin/be-grid.js"></script>
<script src="/admin/app.js"></script>
<script src="/admin/controllers/dashboard.js"></script>
<script src="/admin/controllers/blogs.js"></script>
<script src="/admin/controllers/posts.js"></script>
<script src="/admin/controllers/pages.js"></script>
<script src="/admin/controllers/tags.js"></script>
<script src="/admin/controllers/categories.js"></script>
<script src="/admin/controllers/comments.js"></script>
<script src="/admin/controllers/users.js"></script>
<script src="/admin/controllers/roles.js"></script>
<script src="/admin/controllers/profile.js"></script>
<script src="/admin/controllers/settings.js"></script>
<script src="/admin/controllers/packages.js"></script>
<script src="/admin/controllers/common.js"></script>
<script src="/admin/services.js"></script>
<script src="/scripts/bootstrap.js"></script>
<script src="/scripts/moment.js"></script>
</body>
</html>
PS:這個東西沒什么難度,邏輯都在倉庫中,要源碼的同學(xué)我后續(xù)分離出來了再貼出來。當(dāng)然這個又很多方式,我也不是要秀什么框架,但我目前項目的需求是要這么分開的。一個控制器是可用解決所有問題,但我其他模型也要分頁又要便于測試難道我都寫在控制器中嗎?
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Linux下以守護(hù)進(jìn)程方式運(yùn)行.NET6
這篇文章介紹了Linux下以守護(hù)進(jìn)程方式運(yùn)行.NET6,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12
asp.net+ajaxfileupload.js 實(shí)現(xiàn)文件異步上傳代碼分享
本文給大家分享一段asp.net基于ajaxfileupload.js實(shí)現(xiàn)文件異步上傳的代碼,本人項目中已經(jīng)在使用的代碼,小伙伴們可以直接移植到自己的項目中去。2014-11-11
ASP.NET實(shí)現(xiàn)用圖片進(jìn)度條顯示投票結(jié)果
ASP.NET實(shí)現(xiàn)用圖片進(jìn)度條顯示投票結(jié)果...2007-06-06
HttpRequest Get和Post調(diào)用其他頁面的方法
HttpRequest Get和Post調(diào)用其他頁面的方法,需要的朋友可以參考一下2013-03-03
asp.net Context.Handler 頁面間傳值方法
很有用的頁面間傳值方法(Context.Handler),使用說明2008-08-08
在ASP.NET Core中應(yīng)用HttpClient獲取數(shù)據(jù)和內(nèi)容
這篇文章主要介紹了在ASP.NET Core中集成和使用HttpClient獲取數(shù)據(jù)和內(nèi)容,幫助大家更好的理解和學(xué)習(xí)使用ASP.NET Core,感興趣的朋友可以了解下2021-03-03
使用ASP.NET.4.5.1+MVC5.0 搭建一個包含 Ninject框架 項目
這篇文章主要介紹了使用ASP.NET.4.5.1+MVC5.0 搭建一個包含 Ninject框架 項目的方法,需要的朋友可以參考下2015-01-01

