很多时候需要这样的功能,对表格进行分页、排序和检索。这个有很多实现的方式,有现成的表格控件、用前端的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> <p 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> <p id=userpart> @Html.Action(UserTable,new{pageIndex=ViewBag.CurrentPage}) </p> <p id=userpager></p> <input type=hidden id=dispalypage value=@ViewBag.displayPage/> <input type=hidden id=page value=@ViewBag.CurrentPage/> <input type=hidden id=currentpage value=@ViewBag.CurrentPage/> </p> <p class=modal fade adduserBoxid=adduser tabindex=1 role=dialog aria-hidden=true> <p class=modal-content> <p class=modal-header> <button type=button class=close data-dismiss=modal aria-hidden=true >×</button> <h4 class=modal-title>Add new User</h4> </p> <p class=modal-body> @{ Html.RenderAction(Create,UserManager); } </p> </p> </p> @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或者右键查看源码都是下面这样子的:
主要的就一个p
<p data-ng-app=blogAdmin data-ng-view= id=ng-view></p>
自我保护倒是蛮好,也就是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> <p id=container class=app-wrapper ltr> <p data-ng-app=blogAdmin data-ng-view= id=ng-view></p> </p> <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:这个东西没什么难度,逻辑都在仓库中,要源码的同学我后续分离出来了再贴出来。当然这个又很多方式,我也不是要秀什么框架,但我目前项目的需求是要这么分开的。一个控制器是可用解决所有问题,但我其他模型也要分页又要便于测试难道我都写在控制器中吗?
原文地址:https://www.jb51.cc/csharp/1193588.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。