很多时候需要这样的功能,对表格进行分页、排序和检索。这个有很多实现的方式,有现成的表格控件、用前端的mvvm,用户控件。但很多时候看着很漂亮的东西你想进一步控制的时候却不那么如意。这里自己实现一次,功能不是高大全,但求一个清楚明白,也欢迎园友拍砖。前端是bootstrap3+jPaginate,后台基于membership。没什么难点。
先上效果图。
分页其实就是处理好 每页项目数、总项目数、总页数、当前页。为了方便复用,就先从仓库开始说起。
一、建立仓库
1.定义Ipager接口,需要分页的模型仓库继承这个接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
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表示顺反排序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
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和我们自定义的不一样,所以存在一个转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
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中更改行列的数目。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public static int UserPageItemCount
{
get
{
if (_userPageItemCount == 0)
{
_userPageItemCount = WebConfigurationManager.AppSettings[ "UserPageItemCount" ] != null ?
Convert.ToInt16(WebConfigurationManager.AppSettings[ "UserPageItemCount" ]) : 5;
}
return _userPageItemCount;
}
set
{
_userPageItemCount = value;
}
}
|
再进行绑定:
1
|
_kernel.Bind<IUsersRepository>().To<UsersRepository>();
|
三、控制器部分
我们需要两个页面,一个主页面Index,一个负责局部刷新的部分视图 UserTable
下面是主要的方法,主要逻辑都在在仓库中处理了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
[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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
<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重新分页一次。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@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 都是自己扩展的一些简单的方法,用于全选和提示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
$( 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框架融合度比较高,它的核心代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@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
1
|
< div data-ng-app = "blogAdmin" data-ng-view = "" id = "ng-view" ></ div >
|
自我保护倒是蛮好,也就是SEO可能有问题。应该还有更好的方式,猿友们指点指点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
<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' ],
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:这个东西没什么难度,逻辑都在仓库中,要源码的同学我后续分离出来了再贴出来。当然这个又很多方式,我也不是要秀什么框架,但我目前项目的需求是要这么分开的。一个控制器是可用解决所有问题,但我其他模型也要分页又要便于测试难道我都写在控制器中吗?
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://www.cnblogs.com/stoneniqiu/p/3713114.html