程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Asp.Net MVC 分頁、檢索、排序整體實現代碼,asp.netmvc

Asp.Net MVC 分頁、檢索、排序整體實現代碼,asp.netmvc

編輯:關於.NET

Asp.Net MVC 分頁、檢索、排序整體實現代碼,asp.netmvc


很多時候需要這樣的功能,對表格進行分頁、排序和檢索。這個有很多實現的方式,有現成的表格控件、用前端的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="/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:這個東西沒什麼難度,邏輯都在倉庫中,要源碼的同學我後續分離出來了再貼出來。當然這個又很多方式,我也不是要秀什麼框架,但我目前項目的需求是要這麼分開的。一個控制器是可用解決所有問題,但我其他模型也要分頁又要便於測試難道我都寫在控制器中嗎?

Demo 下載請戳這裡

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持幫客之家。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved