# MVC 搭配 Ajax 實作搜尋分頁功能 ( X.PagedList ) ###### tags: `實作功能` ## 功能展示 ![](https://i.imgur.com/w8QwI8W.png) --- ## 使用情況 資料量大,卻不想要一次資料全部撈完造成效能問題,**PagedList 會分頁撈取資料,而不是全部撈完才分頁。** --- ## 安裝 以前是 ~~[PagedList](https://github.com/troygoode/PagedList)~~,已經停止更新。 目前使用 [X.PagedList](https://github.com/dncuug/X.PagedList) ### Bootstrap3 直接裝 X.PagedList.Mvc 會自己幫你裝好其他的 ### Bootstrap4 ![](https://i.imgur.com/ZvAYf1M.png) 1. 裝 X.PagedList.Mvc ( 會自己幫你裝好 X.PagedList ) 2. 裝 [X.PagedList.Mvc.Bootstrap4](https://github.com/lettucebo/X.PagedList.Mvc.Bootstrap4) ※這時的 X.PagedList.Mvc 最新版為 v7.9.0。會裝舊版的 X.PagedList.Mvc 是因為使用 X.PagedList.Mvc.Bootstrap4 的搭配使用會有問題 ( 對應不到 PagedList 的 PagedListRenderOptionsBase ),不知道會不會更新修掉。 --- ## Model ``` public class SearchFilterViewModel { public string Name { get; set; } public string Email { get; set; } public string NationCode { get; set; } public string CellPhone { get; set; } } ``` --- ## View ### Index ``` @{ ViewBag.Title = "會員列表"; } <!DOCTYPE html> <head> @section styles{ } </head> <body> @section scripts{ <script> function Search() { // 若 hash 沒資料,預設取第 1 頁 // hash = #,瀏覽器解讀為位置識別符號 // # 是用來指導瀏覽器動作的,對伺服器端完全無用。所以,HTTP請求中不包括 # var page = window.location.hash ? window.location.hash.slice(1) : 1; // 取資料 fetchPage(page); } var fetchPage = function (page) { // 準備搜尋條件資料 var filter = { Name: $("#Name").val(), Email: $("#Email").val(), National: $("#National").val(), CellPhone: $("#CellPhone").val(), page: page, } // Ajax 呼叫 $.ajax({ url: '@Url.Action("PagedPartial", "Member")', data: filter, type: 'Post', success: function (resultHtml) { // 取得資料後將目前 hash 重設 window.location.hash = page; // 將 PartialView 資料寫入 div id="MemberDatas" 的區塊 $('#MemberDatas').html(resultHtml); // 重設頁碼按鈕 $('#MemberDatas .pagination li a').each(function (i, item) { // 若是有超連結的頁碼 var hyperLinkUrl = $(item).attr('href'); if (typeof hyperLinkUrl !== 'undefined' && hyperLinkUrl !== false) { // 取得當前按鈕(<a>)的對應頁碼 var pageNumber = $(item).attr('href'); // 將頁碼按鈕的 href 去除 $(item).attr('href', '#'); // 設定按下頁碼事件 $(item).click(function (event) { // 停止事件的默認動作,例如有時候我們會利用連結的 <a> 來當作按鈕, // 他本身 DOM 就擁有連結的功能,但是有時候我們會為他新增 onclick 的事件, // 而只要在該 <a> 觸發的事件中加入event.preventDefault(), // 就不會在執行他默認的動作,也就是不會再執行「連結到某個網址」這個動作。 event.preventDefault(); // 取得按下的頁碼的資料 fetchPage(pageNumber); }); } }); } }); }; </script> } <div class="border border-dark bg-dark text-white rounded p-3"> <div class="row"> <div class="col-sm-4 col-md-3 col-lg-3"> <label class="col-form-label">姓名</label> <div> @Html.TextBox("Name", null, new { @class = "form-control", onkeyup = "Search()" }) </div> </div> <div class="col-sm-8 col-md-4 col-lg-4"> <label class="col-form-label">Email</label> <div> @Html.TextBox("Email", null, new { @class = "form-control" }) </div> </div> <div class="col-sm-3 col-md-3 col-lg-2"> <label class="col-form-label">國碼</label> <select name="National" placeholder="國籍" class="form-control"> <option></option> <option value="886">台灣 +886</option> </select> </div> <div class="form-group col-sm-6 col-md-3 col-lg-3"> <label class="col-form-label">電話</label> <div> @Html.TextBox("CellPhone", null, new { @class = "form-control" }) </div> </div> <div class="col-sm-4 col-md-2 col-lg-2 d-flex align-items-center"> <button class="btn btn-success" onclick="Search()"><i class="fas fa-search fa-lg"></i>搜尋</button> </div> </div> </div> <hr /> <div id="MemberDatas"> </div> </body> ``` ### PartialView (SearchResult.cshtml) ``` @model IPagedList<MemberModel> @using X.PagedList; @using X.PagedList.Mvc; @using X.PagedList.Mvc.Bootstrap4; @Html.PagedListPager((IPagedList)Model, page => page.ToString(), Bootstrap4PagedListRenderOptions.Classic) <table class="table table-bordered table-hover table-sm"> <thead> <tr> <th nowrap="nowrap" style="width:20%">姓名</th> <th nowrap="nowrap" style="width:30%">Email</th> <th nowrap="nowrap" style="width:10%">電話(國碼)</th> <th nowrap="nowrap" style="width:20%">電話(號碼)</th> <th nowrap="nowrap" style="width:20%"></th> </tr> </thead> <tbody> @if (!Model.HasItems()) { <tr> <td colspan="5" class="text-center"> 查無會員資料 </td> </tr> } else { foreach (var data in Model) { <tr> <td nowrap="nowrap">@data.Name</td> <td nowrap="nowrap">@data.Email</td> <td nowrap="nowrap">+@data.NationCode</td> <td nowrap="nowrap">@data.CellPhone</td> <td nowrap="nowrap"> <a href="@(Url.Action("Profile", "Member") + "?memberId=" + data.Id)" class="btn btn-info"><i class="fa fa-eye"></i> 檢視</a> </td> </tr> } } </tbody> </table> @Html.PagedListPager((IPagedList)Model, page => page.ToString(), Bootstrap4PagedListRenderOptions.ClassicPlusFirstAndLast) ``` --- ## Controller ### Index ``` public ActionResult Index() { return View(); } ``` ### PagedPartial ( 回傳 SearchResult.cshtml ) ``` [HttpPost] public ActionResult PagedPartial(SearchFilterViewModel searchFilter, int? page) { #region 找出符合篩選條件的資料 var memberFilter = new Repositories.Filters.MemberFilter(); if (!string.IsNullOrEmpty(searchFilter.Name)) memberFilter.Name = searchFilter.Name; if (!string.IsNullOrEmpty(searchFilter.Email)) memberFilter.Email = searchFilter.Email; if (!string.IsNullOrEmpty(searchFilter.NationCode)) memberFilter.NationCode = searchFilter.NationCode; if (!string.IsNullOrEmpty(searchFilter.CellPhone)) memberFilter.CellPhone = searchFilter.CellPhone; var members = _memberService.Search(memberFilter); if (members == null) members = new List<MemberModel>(); #endregion #region 將資料轉為 PagedList 的資料 var pageNumber = page ?? 1;// 若無傳入 Page,預設查詢第1頁 var onePageOfMembers = members.ToPagedList(pageNumber, 1); // 參數說明: ToPagedList( 第幾頁 , 一頁要顯示多少資料 ) #endregion return PartialView("SearchResult", onePageOfMembers); } ```