利用Bootstrap Paginator插件和KnockoutJS完成分頁功能

  在最近一個項目中,須要結合一堆條件查詢並對查詢的結果數據完成一個簡單分頁功能,但是作着作着,本身的思路愈來愈模糊,作到心態崩潰!!! 哈哈,特此花點時間從新總結,並從最簡單的分頁,而後向多條件查詢分頁慢慢過渡,或許有人以爲這個很簡單(能夠繞道啦,哈哈),倒是對基礎知識的一次學習過程。

  Demo地址:https://gitee.com/530521314/Partner.TreasureChest/tree/master/Pagination/html

  本文地址:http://www.javashuo.com/article/p-ogyapptc-ca.html前端

 

1、環境介紹

  分頁功能不少已有的很完美的插件或是第三方應用包都可以完美實現,我在此利用了一些前端插件來完成分頁功能。java

  前端的Bootstrap Paginator插件完成前端分頁數字之類的切換展現;jquery

  利用knockout.js插件完成分頁數據的綁定;git

  在後端,利用asp.net core mvc 完成分頁信息的接收和處理工做。ajax

 

2、簡單分頁

  完成對已有數據的分頁功能,不帶條件查詢。json

  首先,一上來即是完成數據綁定工做:bootstrap

1   bookList: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model))),//展現數據
2   pageEntity: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(new PageRequestViewModel()))),//分頁信息

    頁面剛展現的時候得有分頁數據吧,能夠在當頁面展現的時候,數據也帶過來了,也能夠頁面展現後,再經過ajax去後臺調用,我選擇後者。後端

  在頁面啓動時,調用該函數完成初始化頁面數據。mvc

 1     getBookData: function () {
 2         var pageEntity = ko.mapping.toJS(viewModel.pageEntity);
 3         $.ajax({
 4             url: '@Url.Action("SampleGetData")',
 5             type: 'POST',
 6             dataType: 'json',
 7             data: pageEntity,
 8             success: function (result) {
 9                 ko.mapping.fromJS(result.data, viewModel.bookList);
10                 options.totalPages = result.totalCount > 0 ? result.totalCount % options.numberOfPages == 0 ?
11                     result.totalCount / options.numberOfPages : (result.totalCount / options.numberOfPages) + 1 : 1;
12                 $('#pagination').bootstrapPaginator(options);
13             }
14         });
15     }

   分頁信息(當前頁面,頁面展現數據條數)帶過去,後臺根據分頁信息完成數據查詢,並得到總的記錄條數用於前端頁面計算總頁數。

 1     [HttpPost]
 2     public IActionResult SampleGetData(PageRequestViewModel pageEntity)
 3     {
 4         var bookList = PageDataSeed.GetPageDataList()
 5             .Skip((pageEntity.PageIndex - 1) * pageEntity.PageSize)
 6             .Take(pageEntity.PageSize);
 7 
 8         var pageResultViewModel = new PageResultViewModel<Book>()
 9         {
10             PageIndex = pageEntity.PageIndex,
11             PageSize = pageEntity.PageSize,
12             TotalCount = PageDataSeed.GetPageDataList().Count(),
13             Data = bookList
14         };
15 
16         return Json(pageResultViewModel);
17     }

 根據分頁信息查詢也就搞定了,當點擊底部的頁面碼的時候得改變當前分頁信息,而後要切換當前分頁信息所對應的數據出來,在Bootstrap paginator插件中,點擊頁面碼有一個函數onPageClicked,點擊具體的某一頁後,根據參數page得到頁面,改變當前展現的頁面碼數字,並對分頁信息修改,而後再次調用ajax得到新數據。

1     onPageClicked: function (event, originalEvent, type, page) {
2         options.currentPage = page;
3         viewModel.pageEntity.PageIndex = page;
4         viewModel.getBookData();
5     },

  至此,簡單分頁功能便搞定了,在此實現中,偏重於前端實現分頁邏輯,後臺只是取得相應的數據。

  

3、單條件查詢分頁

  複製一份簡單分頁後,改造下加入一個根據書名條件項,查詢後完成分頁功能。

  首先加入書名綁定,在此用了兩個書名,第二個是有目的性的留着,也只是個人理解,條件查詢後,若是底部展現有多頁,那麼我在點擊每一頁的時候,個人查詢條件不能動吧,基於此考慮的。

1     bookName: ko.observable(),
2     bookNameBackup: ko.observable(),

  數據查詢部分改動不大,主要是把查詢條件加入進來,所以只改動data參數便可。

 1     getBookData: function () {
 2         var pageEntity = ko.mapping.toJS(viewModel.pageEntity);
 3         $.ajax({
 4             url: '@Url.Action("SingleQueryGetData")',
 5             type: 'POST',
 6             dataType: 'json',
 7             data: {"pageEntity":pageEntity, "bookName":viewModel.bookName()},
 8             success: function (result) {
 9                 ko.mapping.fromJS(result.data, viewModel.bookList);
10                 options.totalPages = result.totalCount > 0 ? result.totalCount % options.numberOfPages == 0 ?
11                     result.totalCount / options.numberOfPages : (result.totalCount / options.numberOfPages) + 1 : 1;
12                 $('#pagination').bootstrapPaginator(options);
13             }
14         });
15     },

  前端Html部分加入單條件項,以書名爲例,查詢按鈕綁定點擊後的觸發函數

1     <div class="form-group">
2         <label for="bookName" class="col-sm-2 control-label">書名</label>
3         <div class="col-sm-2">
4             <input type="text" class="form-control" id="bookName" data-bind="value:bookName">
5         </div>
6         <button class="btn btn-primary col-sm-1" data-bind="click:queryBookList">查詢</button>
7     </div>

  點擊查詢後執行函數,將當前頁面重置爲1,查詢數據,並記錄該次查詢的查詢條件。

1   //查詢
2     queryBookList: function () {
3         options.currentPage = 1;
4         viewModel.pageEntity.PageIndex = options.currentPage;
5         viewModel.getBookData();
6         viewModel.bookNameBackup(viewModel.bookName());//記錄查詢條件,分頁點擊時須要用到
7     }

  查詢完畢,而後假設底部還存在不少頁面碼能夠選擇,當咱們點擊頁面碼的時候,由於查詢條件仍然存在,咱們點擊後仍然會完成分頁功能,可是!!!

  當把查詢條件清空,好比在此demo中,把書名置空,此時不點查詢按鈕,而是直接點擊頁面碼,那狀況會如何呢,查詢條件已經沒了;

  或是說查詢條件爲空時,輸入查詢條件,不點查詢按鈕,直接點擊頁面碼;

  這都是不合理的情形,點擊頁面碼的時候確定得保證原查詢條件的存在,至少我是這麼想的,或許您有更好的建議,請告訴我,十分感謝。這也就是我在以前設置了一個監控對象bookNameBackup的緣由,備份查詢條件,防止點擊頁碼切換時查詢條件變動的情形。

  前端已經改好了,而後進入後端來改一下,先對條件判空處理,而後執行相應的邏輯。

 1     [HttpPost]
 2     public IActionResult SingleQueryGetData(PageRequestViewModel pageEntity, string bookName)
 3     {
 4         IEnumerable<Book> bookList = PageDataSeed.GetPageDataList();
 5         PageResultViewModel<Book> pageResultViewModel = null;
 6 
 7         if (!string.IsNullOrEmpty(bookName))
 8             bookList = bookList.Where(b => b.BookName.Contains(bookName));
 9 
10         var books = bookList.Skip((pageEntity.PageIndex - 1) * pageEntity.PageSize)
11                 .Take(pageEntity.PageSize);
12 
13         pageResultViewModel = new PageResultViewModel<Book>()
14         {
15             PageIndex = pageEntity.PageIndex,
16             PageSize = pageEntity.PageSize,
17             TotalCount = bookList.Count(),
18             Data = books
19         };
20 
21         return Json(pageResultViewModel);
22     }

  單條件查詢分頁功能也就搞定了,查詢和點擊頁面碼所執行的邏輯是不同的,雖然都調用到了最終的數據查詢方法,可是對於條件的處理是不同的。

   

4、多條件查詢分頁

  對單條件查詢分頁下多加入幾個條件,進入到多條件查詢,變化其實不大,只是爲了方便管理如此多的查詢條件,改爲了以對象形式管理

  首先綁定查詢對象信息,該對象中包括了三個查詢條件,書名,做者,出版社,仍然設置一個備份對象,緣由和單條件查詢下是同樣的。

1     queryItemEntity: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(new QueryItemViewModel()))),//查詢條件信息
2     queryItemEntityBackup: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(new QueryItemViewModel()))),//查詢條件信息備份

  頁面的查詢條件多了,經過queryItemEntity爲前綴展現,也方便維護

 1     <div id="queryItem" class="form-horizontal">
 2         <div class="form-group">
 3             <label for="bookName" class="col-sm-2 control-label">書名</label>
 4             <div class="col-sm-2">
 5                 <input type="text" class="form-control" id="bookName" data-bind="value:queryItemEntity.BookName">
 6             </div>
 7             <label for="author" class="col-sm-2 control-label">做者</label>
 8             <div class="col-sm-2">
 9                 <input type="text" class="form-control" id="author" data-bind="value:queryItemEntity.Author">
10             </div>
11             <label for="press" class="col-sm-2 control-label">出版社</label>
12             <div class="col-sm-2">
13                 <input type="text" class="form-control" id="press" data-bind="value:queryItemEntity.Press">
14             </div>
15         </div>
16         <button class="btn btn-primary" data-bind="click:queryBookList">查詢</button>
17     </div>

  查詢條件改動,也使得數據查詢部分的條件改變了,將查詢條件總體封裝,而不是零散的傳遞,改動之處加入了第三行將ko上的查詢條件信息轉換爲JS對象和改變了參數data的值。

 1   getBookData: function () {
 2         var pageEntity = ko.mapping.toJS(viewModel.pageEntity);
 3         var queryItemEntity = ko.mapping.toJS(viewModel.queryItemEntity);
 4 
 5         $.ajax({
 6             url: '@Url.Action("MultipleQueryGetData")',
 7             type: 'POST',
 8             dataType: 'json',
 9             data: { "pageEntity": pageEntity, "queryItemEntity": queryItemEntity},
10             success: function (result) {
11                 ko.mapping.fromJS(result.data, viewModel.bookList);
12                 options.totalPages = result.totalCount > 0 ? result.totalCount % options.numberOfPages == 0 ?
13                     result.totalCount / options.numberOfPages : (result.totalCount / options.numberOfPages) + 1 : 1;
14                 $('#pagination').bootstrapPaginator(options);
15             }
16         });
17     },

   點擊按鈕查詢處的邏輯仍是沒有改變,仍然是查詢記錄並將查詢條件備份,用於分頁控件中頁面碼的點擊函數。

1     //查詢
2     queryBookList: function () {
3         options.currentPage = 1;
4         viewModel.pageEntity.PageIndex = options.currentPage;
5         viewModel.getBookData();
6         ko.mapping.fromJS(viewModel.queryItemEntity, viewModel.queryItemEntityBackup);//記錄查詢條件,分頁點擊時須要用到
7     }

   對於前端來說改動並非很大,無非是將查詢條件封裝一下,一樣後端的改動只是多個查詢條件的過濾,依次比對三個查詢條件是否爲空,並挨個去完成查詢的過濾。

 1     [HttpPost]
 2     public IActionResult MultipleQueryGetData(PageRequestViewModel pageEntity, QueryItemViewModel queryItemEntity)
 3     {
 4         var bookList = PageDataSeed.GetPageDataList();
 5 
 6         #region 條件過濾
 7         if (!string.IsNullOrEmpty(queryItemEntity.BookName))
 8             bookList = bookList.Where(b => b.BookName.Contains(queryItemEntity.BookName)).ToList();
 9         if (!string.IsNullOrEmpty(queryItemEntity.Author))
10             bookList = bookList.Where(b => b.Author.Contains(queryItemEntity.Author)).ToList();
11         if (!string.IsNullOrEmpty(queryItemEntity.Press))
12             bookList = bookList.Where(b => b.Press.Contains(queryItemEntity.Press)).ToList();
13         #endregion
14 
15         var books = bookList.Skip((pageEntity.PageIndex - 1) * pageEntity.PageSize).Take(pageEntity.PageSize);
16 
17         var pageResultViewModel = new PageResultViewModel<Book>()
18         {
19             PageIndex = pageEntity.PageIndex,
20             PageSize = pageEntity.PageSize,
21             TotalCount = bookList.Count(),
22             Data = books
23         };
24 
25         return Json(pageResultViewModel);
26     }

  多條件查詢分頁的效果展現

  

  至此,查詢功能算是簡單完成了,或許還有漏洞地方,沒有發現,特別是邏輯漏洞,防不勝防,望多指教,感謝。

  設計一個小Demo一方面是對分頁功能進行一下總結,以防本身若干天或是若干年後還須要,能夠回來看看,一方面也是若是有須要的朋友能夠加快編碼和設計的過程。

  碼雲上存放Demo的地址:https://gitee.com/530521314/Partner.TreasureChest/tree/master/Pagination/

 

2018-6-24,望技術有成後能回來看見本身的腳步
相關文章
相關標籤/搜索