Bootstrap與KnockoutJs相結(jié)合實(shí)現(xiàn)分頁(yè)效果實(shí)例詳解
來(lái)源:易賢網(wǎng) 閱讀:1134 次 日期:2016-07-06 10:48:02
溫馨提示:易賢網(wǎng)小編為您整理了“Bootstrap與KnockoutJs相結(jié)合實(shí)現(xiàn)分頁(yè)效果實(shí)例詳解”,方便廣大網(wǎng)友查閱!

KnockoutJS是一個(gè)JavaScript實(shí)現(xiàn)的MVVM框架。接下來(lái)通過(guò)本文給大家介紹Bootstrap與KnockoutJs相結(jié)合實(shí)現(xiàn)分頁(yè)效果,對(duì)bootstrap knockoutjs相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧

KnockoutJS是一個(gè)JavaScript實(shí)現(xiàn)的MVVM框架。非常棒。比如列表數(shù)據(jù)項(xiàng)增減后,不需要重新刷新整個(gè)控件片段或自己寫JS增刪節(jié)點(diǎn),只要預(yù)先定義模板和符合其語(yǔ)法定義的屬性即可。簡(jiǎn)單的說(shuō),我們只需要關(guān)注數(shù)據(jù)的存取。

一、引言

由于最近公司的系統(tǒng)需要改版,改版的新系統(tǒng)我打算使用KnockoutJs來(lái)制作Web前端。在做的過(guò)程中,遇到一個(gè)問(wèn)題——如何使用KnockoutJs來(lái)完成分頁(yè)的功能。在前一篇文章中并沒(méi)有介紹使用KnockoutJs來(lái)實(shí)現(xiàn)分頁(yè),所以在這篇文章中,將補(bǔ)充用KnockoutJs+Bootstrap來(lái)實(shí)現(xiàn)數(shù)據(jù)的分頁(yè)顯示。

二、使用KnockoutJs實(shí)現(xiàn)分頁(yè)

這里采用了兩種方式來(lái)實(shí)現(xiàn)分頁(yè),第一種是將所有數(shù)據(jù)加載出來(lái),然后再將所有數(shù)據(jù)分頁(yè)顯示;第二種是每次都只加載部分?jǐn)?shù)據(jù),每次請(qǐng)求都重新加載后面的數(shù)據(jù)。

對(duì)于這兩種方式,使用Razor方式實(shí)現(xiàn)的分頁(yè)一般都會(huì)采用第二種方式來(lái)實(shí)現(xiàn)分頁(yè),但是對(duì)于單頁(yè)面程序來(lái)說(shuō),第一種實(shí)現(xiàn)方式也有其好處,對(duì)于不是非常大量的數(shù)據(jù)完全可以采用第一種實(shí)現(xiàn)方式,因?yàn)檫@樣的話,后面的數(shù)據(jù)的加載,用戶體驗(yàn)非常的流暢。所以這里將分別介紹這兩種實(shí)現(xiàn)方式。

2.1 每次加載部分?jǐn)?shù)據(jù)的實(shí)現(xiàn)

這里的后端代碼采用的是前一篇文章的代碼,只是多加了一些示例數(shù)據(jù)而已。具體的后端實(shí)現(xiàn)代碼為:

/// <summary>

 /// Web API 服務(wù),為Web前端提供數(shù)據(jù)服務(wù)

 /// </summary>

 public class TaskController : ApiController

 {

  private readonly TaskRepository _taskRepository = TaskRepository.Current;

  public IEnumerable<Task> GetAll()

  {

   return _taskRepository.GetAll().OrderBy(a => a.Id);

  }

  [Route("api/task/GetByPaged")]

  public PagedModel GetAll([FromUri]int pageIndex)

  {

   const int pageSize = 3;

   int totalCount;

   var tasks = _taskRepository.GetAll(pageIndex, pageSize, out totalCount).OrderBy(a => a.Id);

   var pageData = new PagedModel()

   {

    PageIndex = pageIndex,

    PagedData = tasks.ToList(),

    TotalCount = totalCount,

    PageCount = (totalCount+ pageSize -1) / pageSize

   };

   //返回?cái)?shù)據(jù)

   return pageData;

  }

 }

/// <summary>

 /// 任務(wù)倉(cāng)儲(chǔ),封裝了所有關(guān)于數(shù)據(jù)庫(kù)的操作

 /// </summary>

 public class TaskRepository

 {

  #region Static Filed

  private static Lazy<TaskRepository> _taskRepository = new Lazy<TaskRepository>(() => new TaskRepository());

  public static TaskRepository Current

  {

   get { return _taskRepository.Value; }

  }

  #endregion

  #region Fields

  private readonly List<Task> _tasks = new List<Task>()

  {

   new Task

   {

    Id =1,

    Name = "創(chuàng)建一個(gè)SPA程序",

    Description = "SPA(single page web application),SPA的優(yōu)勢(shì)就是少量帶寬,平滑體驗(yàn)",

    Owner = "Learning hard",

    FinishTime = DateTime.Parse(DateTime.Now.AddDays(1).ToString(CultureInfo.InvariantCulture))

   },

   new Task

   {

    Id =2,

    Name = "學(xué)習(xí)KnockoutJs",

    Description = "KnockoutJs是一個(gè)MVVM類庫(kù),支持雙向綁定",

    Owner = "Tommy Li",

    FinishTime = DateTime.Parse(DateTime.Now.AddDays(2).ToString(CultureInfo.InvariantCulture))

   },

   new Task

   {

    Id =3,

    Name = "學(xué)習(xí)AngularJS",

    Description = "AngularJs是MVVM框架,集MVVM和MVC與一體。",

    Owner = "李志",

    FinishTime = DateTime.Parse(DateTime.Now.AddDays(3).ToString(CultureInfo.InvariantCulture))

   },

   new Task

   {

    Id =4,

    Name = "學(xué)習(xí)ASP.NET MVC網(wǎng)站",

    Description = "Glimpse是一款.NET下的性能測(cè)試工具,支持asp.net 、asp.net mvc, EF等等,優(yōu)勢(shì)在于,不需要修改原項(xiàng)目任何代碼,且能輸出代碼執(zhí)行各個(gè)環(huán)節(jié)的執(zhí)行時(shí)間",

    Owner = "Tonny Li",

    FinishTime = DateTime.Parse(DateTime.Now.AddDays(4).ToString(CultureInfo.InvariantCulture))

   },

   new Task

   {

    Id =5,

    Name = "測(cè)試任務(wù)1",

    Description = "測(cè)試任務(wù)1",

    Owner = "李志",

    FinishTime = DateTime.Parse(DateTime.Now.AddDays(5).ToString(CultureInfo.InvariantCulture))

   },

   new Task

   {

    Id =6,

    Name = "測(cè)試任務(wù)2",

    Description = "測(cè)試任務(wù)2",

    Owner = "李志",

    FinishTime = DateTime.Parse(DateTime.Now.AddDays(6).ToString(CultureInfo.InvariantCulture))

   },

   new Task

   {

    Id =7,

    Name = "測(cè)試任務(wù)3",

    Description = "測(cè)試任務(wù)3",

    Owner = "李志",

    FinishTime = DateTime.Parse(DateTime.Now.AddDays(7).ToString(CultureInfo.InvariantCulture))

   },

  };

  #endregion

  #region Public Methods

  public IEnumerable<Task> GetAll()

  {

   return _tasks;

  }

  public IEnumerable<Task> GetAll(int pageNumber, int pageSize, out int totalCount)

  {

   var skip = (pageNumber - 1) * pageSize;

   var take = pageSize;

   totalCount = _tasks.Count;

   return _tasks.Skip(skip).Take(take);

  }

  public Task Get(int id)

  {

   return _tasks.Find(p => p.Id == id);

  }

  public Task Add(Task item)

  {

   if (item == null)

   {

    throw new ArgumentNullException("item");

   }

   item.Id = _tasks.Count + 1;

   _tasks.Add(item);

   return item;

  }

  public void Remove(int id)

  {

   _tasks.RemoveAll(p => p.Id == id);

  }

  public bool Update(Task item)

  {

   if (item == null)

   {

    throw new ArgumentNullException("item");

   }

   var taskItem = Get(item.Id);

   if (taskItem == null)

   {

    return false;

   }

   _tasks.Remove(taskItem);

   _tasks.Add(item);

   return true;

  }

  #endregion

 }

Web前端的實(shí)現(xiàn)代碼:

@{

ViewBag.Title = "Index2";

Layout = "~/Views/Shared/_Layout.cshtml";

}

<div id="list2">

<h2>分頁(yè)第二種實(shí)現(xiàn)方式——任務(wù)列表</h2>

<div class="table-responsive">

<table class="table table-striped">

<thead>

<tr>

<th>編號(hào)</th>

<th>名稱</th>

<th>描述</th>

<th>負(fù)責(zé)人</th>

<th>創(chuàng)建時(shí)間</th>

<th>完成時(shí)間</th>

<th>狀態(tài)</th>

</tr>

</thead>

<tbody data-bind="foreach:pagedList">

<tr>

<td data-bind="text: id"></td>

<td><a data-bind="text: name"></a></td>

<td data-bind="text: description"></td>

<td data-bind="text: owner"></td>

<td data-bind="text: creationTime"></td>

<td data-bind="text: finishTime"></td>

<td data-bind="text: state"></td>

</tr>

</tbody>

<tbody data-bind="if: loadingState">

<tr>

<td colspan="8" class="text-center">

<img width="60" src="/images/loading.gif" />

</td>

</tr>

</tbody>

<tfoot data-bind="ifnot:loadingState">

<tr>

<td colspan="8">

<div class="pull-right">

<div>總共有<span data-bind="text: totalCount"></span>條記錄, 每頁(yè)顯示:<span data-bind="text: pageSize"></span>條</div>

<div>

<ul class="pagination">

<li data-bind="css: { disabled: pageIndex() === 1 }"><a href="#" data-bind="click: previous">«</a></li>

</ul>

<ul data-bind="foreach: allPages" class="pagination">

<li data-bind="css: { active: $data.pageNumber === ($root.pageIndex()) }"><a href="#" data-bind="text: $data.pageNumber, click: function() { $root.gotoPage($data.pageNumber); }"></a></li>

</ul>

<ul class="pagination"><li data-bind="css: { disabled: pageIndex() === pageCount }"><a href="#" data-bind="click: next">»</a></li></ul>

</div>

</div>

</td>

</tr>

</tfoot>

</table>

</div>

</div>

對(duì)應(yīng)的Js實(shí)現(xiàn)為:

// 實(shí)現(xiàn)分頁(yè)的第二種方式

var ListViewModel2 = function() {

//viewModel本身。用來(lái)防止直接使用this的時(shí)候作用域混亂

var self = this;

self.loadingState = ko.observable(true);

self.pageSize = ko.observable(3);

//數(shù)據(jù)

this.pagedList = ko.observableArray();

//要訪問(wèn)的頁(yè)碼

this.pageIndex = ko.observable(1);

//總頁(yè)數(shù)

this.pageCount = ko.observable(1);

//頁(yè)碼數(shù)

this.allPages = ko.observableArray();

//當(dāng)前頁(yè)

this.currengePage = ko.observable(1);

self.totalCount = ko.observable(1);

this.refresh = function() {

//限制請(qǐng)求頁(yè)碼在該數(shù)據(jù)頁(yè)碼范圍內(nèi)

if (self.pageIndex() < 1)

self.pageIndex(1);

if (self.pageIndex() > self.pageCount()) {

self.pageIndex(self.pageCount());

}

//post異步加載數(shù)據(jù)

sendAjaxRequest("GET", function (data) {

// 加載新的數(shù)據(jù)前,先移除原先的數(shù)據(jù)

self.pagedList.removeAll();

self.allPages.removeAll();

self.totalCount(data.totalCount);

self.pageCount(data.pageCount);

self.loadingState(false);

for (var i = 1; i <= data.pageCount; i++) {

//裝填頁(yè)碼

self.allPages.push({ pageNumber: i });

}

//for...in 語(yǔ)句用于對(duì)數(shù)組或者對(duì)象的屬性進(jìn)行循環(huán)操作。

//for ... in 循環(huán)中的代碼每執(zhí)行一次,就會(huì)對(duì)數(shù)組的元素或者對(duì)象的屬性進(jìn)行一次操作。

for (var i in data.pagedData) {

//裝填數(shù)據(jù)

self.pagedList.push(data.pagedData[i]);

}

}, 'GetByPaged', { 'pageIndex': self.pageIndex() });

};

//請(qǐng)求第一頁(yè)數(shù)據(jù)

this.first = function() {

self.pageIndex(1);

self.refresh();

};

//請(qǐng)求下一頁(yè)數(shù)據(jù)

this.next = function() {

self.pageIndex(this.pageIndex() + 1);

self.refresh();

};

//請(qǐng)求先前一頁(yè)數(shù)據(jù)

this.previous = function() {

self.pageIndex(this.pageIndex() - 1);

self.refresh();

};

//請(qǐng)求最后一頁(yè)數(shù)據(jù)

this.last = function() {

self.pageIndex(this.pageCount() - 1);

self.refresh();

};

//跳轉(zhuǎn)到某頁(yè)

this.gotoPage = function (data, event) {

self.pageIndex(data);

self.refresh();

};

};

function sendAjaxRequest(httpMethod, callback, url, reqData) {

$.ajax("/api/task" + (url ? "/" + url : ""), {

type: httpMethod,

success: callback,

data: reqData

});

}

$(document).ready(function () {

var viewModel = new ListViewModel2();

viewModel.refresh();

if ($('#list2').length)

ko.applyBindings(viewModel, $('#list2').get(0));

});

這里介紹了下使用KnockoutJs實(shí)現(xiàn)分頁(yè)功能的實(shí)現(xiàn)思路:

1.頁(yè)面加載完成之后,發(fā)起Ajax請(qǐng)求去異步調(diào)用REST 服務(wù)來(lái)請(qǐng)求部分?jǐn)?shù)據(jù)。

2.然后將請(qǐng)求的數(shù)據(jù)通過(guò)KnockoutJs綁定顯示。

3.將對(duì)應(yīng)的分頁(yè)信息綁定到Bootstrap分頁(yè)中

4.當(dāng)用戶點(diǎn)擊翻頁(yè)時(shí),再發(fā)起一個(gè)Ajax請(qǐng)求去異步調(diào)用Rest服務(wù)請(qǐng)求數(shù)據(jù),再將請(qǐng)求的數(shù)據(jù)顯示出來(lái)。

這上面是描述的代碼的調(diào)用邏輯關(guān)系,你可以參考對(duì)應(yīng)的JS代碼來(lái)理解上面的描述。到此我們第二種實(shí)現(xiàn)方式就實(shí)現(xiàn)完成了。

2.2 第一次加載所有數(shù)據(jù),然后將所有數(shù)據(jù)分頁(yè)顯示

接下來(lái)就介紹了第一種實(shí)現(xiàn)方式,這樣的實(shí)現(xiàn)方式,用戶只會(huì)在第一次的時(shí)候才會(huì)感覺(jué)到數(shù)據(jù)加載中,翻頁(yè)過(guò)程中感覺(jué)不到頁(yè)面的加載,這樣對(duì)于一些本身數(shù)據(jù)了不是太多的情況下,對(duì)于用戶的感覺(jué)也是更加流暢的。

其具體的實(shí)現(xiàn)思路,也就是將請(qǐng)求的數(shù)據(jù)不要全部顯示在頁(yè)面上,因?yàn)閿?shù)據(jù)太多,一下子顯示到頁(yè)面中,用戶可能會(huì)眼花繚亂。將數(shù)據(jù)分頁(yè)顯示將使得用戶查看更加清晰。

具體的Web前端Js的實(shí)現(xiàn)代碼為:

var ListViewModel = function () {

var self = this;

window.viewModel = self;

self.list = ko.observableArray();

self.pageSize = ko.observable(3); 

self.pageIndex = ko.observable(0); //要訪問(wèn)的頁(yè)碼

self.totalCount = ko.observable(1); //總記錄數(shù)

self.loadingState = ko.observable(true);

self.pagedList = ko.dependentObservable(function () {

var size = self.pageSize();

var start = self.pageIndex() * size;

return self.list.slice(start, start + size);

});

self.maxPageIndex = ko.dependentObservable(function () {

return Math.ceil(self.list().length / self.pageSize()) - 1;

});

self.previousPage = function () {

if (self.pageIndex() > 0) {

self.pageIndex(self.pageIndex() - 1);

}

};

self.nextPage = function () {

if (self.pageIndex() < self.maxPageIndex()) {

self.pageIndex(self.pageIndex() + 1);

}

};

self.allPages = ko.dependentObservable(function () {

var pages = [];

for (var i = 0; i <= self.maxPageIndex() ; i++) {

pages.push({ pageNumber: (i + 1) });

}

return pages;

});

self.moveToPage = function (index) {

self.pageIndex(index);

};

};

var listViewModel = new ListViewModel();

function bindViewModel() {

sendAjaxRequest("GET", function (data) {

listViewModel.loadingState(false);

listViewModel.list(data);

listViewModel.totalCount(data.length);

if ($('#list').length)

ko.applyBindings(listViewModel, $('#list').get(0));

}, null, null);

}

$(document).ready(function () {

bindViewModel();

});

其前端頁(yè)面的實(shí)現(xiàn)與前面的實(shí)現(xiàn)類似。具體頁(yè)面代碼如下:

@{

ViewBag.Title = "Index";

Layout = "~/Views/Shared/_Layout.cshtml";

}

<div id="list">

<h2>任務(wù)列表</h2>

<div class="table-responsive">

<table class="table table-striped">

<thead>

<tr>

<th>編號(hào)</th>

<th>名稱</th>

<th>描述</th>

<th>負(fù)責(zé)人</th>

<th>創(chuàng)建時(shí)間</th>

<th>完成時(shí)間</th>

<th>狀態(tài)</th>

</tr>

</thead>

<tbody data-bind="foreach:pagedList">

<tr>

<td data-bind="text: id"></td>

<td><a data-bind="text: name"></a></td>

<td data-bind="text: description"></td>

<td data-bind="text: owner"></td>

<td data-bind="text: creationTime"></td>

<td data-bind="text: finishTime"></td>

<td data-bind="text: state"></td>

</tr>

</tbody>

<tbody data-bind="if:loadingState">

<tr>

<td colspan="8" class="text-center">

<img width="60" src="/images/loading.gif" />

</td>

</tr>

</tbody>

<tfoot data-bind="ifnot:loadingState">

<tr>

<td colspan="8">

<div class="pull-right">

<div>總共有<span data-bind="text: totalCount"></span>條記錄, 每頁(yè)顯示:<span data-bind="text: pageSize"></span>條</div>

<div>

<ul class="pagination">

<li data-bind="css: { disabled: pageIndex() === 0 }"><a href="#" data-bind="click: previousPage">«</a></li>

</ul>

<ul data-bind="foreach: allPages" class="pagination">

<li data-bind="css: { active: $data.pageNumber === ($root.pageIndex() + 1) }"><a href="#" data-bind="text: $data.pageNumber, click: function() { $root.moveToPage($data.pageNumber-1); }"></a></li>

</ul>

<ul class="pagination"><li data-bind="css: { disabled: pageIndex() === maxPageIndex() }"><a href="#" data-bind="click: nextPage">»</a></li></ul>

</div>

</div>

</td>

</tr>

</tfoot>

</table>

</div>

</div>

三、運(yùn)行效果

接下來(lái),讓我們看看,使用KnockoutJs實(shí)現(xiàn)的分頁(yè)效果:

名單

四、總結(jié)

到這里,本文要介紹的內(nèi)容就結(jié)束,盡管本文實(shí)現(xiàn)的內(nèi)容相對(duì)比較簡(jiǎn)單,但是對(duì)于一些剛接觸KnockoutJs的朋友來(lái)說(shuō),相信本文的實(shí)現(xiàn)會(huì)是一個(gè)很多的指導(dǎo)。接下來(lái),我將會(huì)為大家分享下AngularJs的相關(guān)內(nèi)容。

以上所述是小編給大家介紹的Bootstrap與KnockoutJs相結(jié)合實(shí)現(xiàn)分頁(yè)效果實(shí)例詳解,希望對(duì)大家有所幫助!

更多信息請(qǐng)查看網(wǎng)絡(luò)編程
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

2025國(guó)考·省考課程試聽(tīng)報(bào)名

  • 報(bào)班類型
  • 姓名
  • 手機(jī)號(hào)
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡(jiǎn)要咨詢 | 簡(jiǎn)要咨詢須知 | 新媒體/短視頻平臺(tái) | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
云南網(wǎng)警備案專用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號(hào):hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報(bào)警專用圖標(biāo)