本文主要包含knockoutjs,knockoutjs中文手册,knockoutjs教程,knockoutjs视频教程,knockoutjs下载等相关知识,Learning hard 希望在学习及工作中可以帮助到您
KnockoutJS是一个JavaScript实现的MVVM框架。非常棒。比如列表数据项增减后,不需要重新刷新整个控件片段或自己写JS增删节点,只要预先定义模板和符合其语法定义的属性即可。简单的说,我们只需要关注数据的存取。
一、引言
由于最近公司的系统需要改版,改版的新系统我打算使用KnockoutJs来制作Web前端。在做的过程中,遇到一个问题——如何使用KnockoutJs来完成分页的功能。在前一篇文章中并没有介绍使用KnockoutJs来实现分页,所以在这篇文章中,将补充用KnockoutJs+Bootstrap来实现数据的分页显示。
二、使用KnockoutJs实现分页
这里采用了两种方式来实现分页,第一种是将所有数据加载出来,然后再将所有数据分页显示;第二种是每次都只加载部分数据,每次请求都重新加载后面的数据。
对于这两种方式,使用Razor方式实现的分页一般都会采用第二种方式来实现分页,但是对于单页面程序来说,第一种实现方式也有其好处,对于不是非常大量的数据完全可以采用第一种实现方式,因为这样的话,后面的数据的加载,用户体验非常的流畅。所以这里将分别介绍这两种实现方式。
2.1 每次加载部分数据的实现
这里的后端代码采用的是前一篇文章的代码,只是多加了一些示例数据而已。具体的后端实现代码为:
/// <summary>
/// Web API 服务,为Web前端提供数据服务
/// </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
};
//返回数据
return pageData;
}
}
/// <summary>
/// 任务仓储,封装了所有关于数据库的操作
/// </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 = "创建一个SPA程序",
Description = "SPA(single page web application),SPA的优势就是少量带宽,平滑体验",
Owner = "Learning hard",
FinishTime = DateTime.Parse(DateTime.Now.AddDays(1).ToString(CultureInfo.InvariantCulture))
},
new Task
{
Id =2,
Name = "学习KnockoutJs",
Description = "KnockoutJs是一个MVVM类库,支持双向绑定",
Owner = "Tommy Li",
FinishTime = DateTime.Parse(DateTime.Now.AddDays(2).ToString(CultureInfo.InvariantCulture))
},
new Task
{
Id =3,
Name = "学习AngularJS",
Description = "AngularJs是MVVM框架,集MVVM和MVC与一体。",
Owner = "李志",
FinishTime = DateTime.Parse(DateTime.Now.AddDays(3).ToString(CultureInfo.InvariantCulture))
},
new Task
{
Id =4,
Name = "学习ASP.NET MVC网站",
Description = "Glimpse是一款.NET下的性能测试工具,支持asp.net 、asp.net mvc, EF等等,优势在于,不需要修改原项目任何代码,且能输出代码执行各个环节的执行时间",
Owner = "Tonny Li",
FinishTime = DateTime.Parse(DateTime.Now.AddDays(4).ToString(CultureInfo.InvariantCulture))
},
new Task
{
Id =5,
Name = "测试任务1",
Description = "测试任务1",
Owner = "李志",
FinishTime = DateTime.Parse(DateTime.Now.AddDays(5).ToString(CultureInfo.InvariantCulture))
},
new Task
{
Id =6,
Name = "测试任务2",
Description = "测试任务2",
Owner = "李志",
FinishTime = DateTime.Parse(DateTime.Now.AddDays(6).ToString(CultureInfo.InvariantCulture))
},
new Task
{
Id =7,
Name = "测试任务3",
Description = "测试任务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
}
</div>
Web前端的实现代码:
@{
ViewBag.Title = "Index2";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="list2">
<h2>分页第二种实现方式——任务列表</h2>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>描述</th>
<th>负责人</th>
<th>创建时间</th>
<th>完成时间</th>
<th>状态</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>条记录, 每页显示:<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>
</div>
对应的Js实现为:
// 实现分页的第二种方式
var ListViewModel2 = function() {
//viewModel本身。用来防止直接使用this的时候作用域混乱
var self = this;
self.loadingState = ko.observable(true);
self.pageSize =

