博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[后端人员耍前端系列]KnockoutJs篇:使用KnockoutJs+Bootstrap实现分页
阅读量:6367 次
发布时间:2019-06-23

本文共 11671 字,大约阅读时间需要 38 分钟。

一、引言

  由于最近公司的系统需要改版,改版的新系统我打算使用KnockoutJs来制作Web前端。在做的过程中,遇到一个问题——如何使用KnockoutJs来完成分页的功能。在前一篇文章中并没有介绍使用KnockoutJs来实现分页,所以在这篇文章中,将补充用KnockoutJs+Bootstrap来实现数据的分页显示。

二、使用KnockoutJs实现分页

  这里采用了两种方式来实现分页,第一种是将所有数据加载出来,然后再将所有数据分页显示;第二种是每次都只加载部分数据,每次请求都重新加载后面的数据。

  对于这两种方式,使用Razor方式实现的分页一般都会采用第二种方式来实现分页,但是对于单页面程序来说,第一种实现方式也有其好处,对于不是非常大量的数据完全可以采用第一种实现方式,因为这样的话,后面的数据的加载,用户体验非常的流畅。所以这里将分别介绍这两种实现方式。

2.1 每次加载部分数据的实现

   这里的后端代码采用的是前一篇文章的代码,只是多加了一些示例数据而已。具体的后端实现代码为:

///     /// Web API 服务,为Web前端提供数据服务    ///     public class TaskController : ApiController    {        private readonly TaskRepository _taskRepository = TaskRepository.Current;        public IEnumerable
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; } }///
/// 任务仓储,封装了所有关于数据库的操作 /// public class TaskRepository { #region Static Filed private static Lazy
_taskRepository = new Lazy
(() => new TaskRepository()); public static TaskRepository Current { get { return _taskRepository.Value; } } #endregion #region Fields private readonly List
_tasks = new List
() { 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
GetAll() { return _tasks; } public IEnumerable
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 }
View Code

  Web前端的实现代码:

@{    ViewBag.Title = "Index2";    Layout = "~/Views/Shared/_Layout.cshtml";}

分页第二种实现方式——任务列表

编号 名称 描述 负责人 创建时间 完成时间 状态
总共有
条记录, 每页显示:

  对应的Js实现为:

// 实现分页的第二种方式var ListViewModel2 = function() {    //viewModel本身。用来防止直接使用this的时候作用域混乱    var self = this;    self.loadingState = ko.observable(true);    self.pageSize = ko.observable(3);    //数据    this.pagedList = ko.observableArray();    //要访问的页码    this.pageIndex = ko.observable(1);    //总页数    this.pageCount = ko.observable(1);    //页码数    this.allPages = ko.observableArray();    //当前页    this.currengePage = ko.observable(1);    self.totalCount = ko.observable(1);    this.refresh = function() {        //限制请求页码在该数据页码范围内        if (self.pageIndex() < 1)            self.pageIndex(1);        if (self.pageIndex() > self.pageCount()) {            self.pageIndex(self.pageCount());        }        //post异步加载数据        sendAjaxRequest("GET", function (data) {            // 加载新的数据前,先移除原先的数据            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++) {                //装填页码                self.allPages.push({ pageNumber: i });            }            //for...in 语句用于对数组或者对象的属性进行循环操作。            //for ... in 循环中的代码每执行一次,就会对数组的元素或者对象的属性进行一次操作。            for (var i in data.pagedData) {                //装填数据                self.pagedList.push(data.pagedData[i]);            }        }, 'GetByPaged', { 'pageIndex': self.pageIndex() });    };        //请求第一页数据    this.first = function() {        self.pageIndex(1);        self.refresh();    };    //请求下一页数据    this.next = function() {        self.pageIndex(this.pageIndex() + 1);        self.refresh();    };        //请求先前一页数据    this.previous = function() {        self.pageIndex(this.pageIndex() - 1);        self.refresh();    };    //请求最后一页数据    this.last = function() {        self.pageIndex(this.pageCount() - 1);        self.refresh();    };        //跳转到某页    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实现分页功能的实现思路:

  1. 页面加载完成之后,发起Ajax请求去异步调用REST 服务来请求部分数据。
  2. 然后将请求的数据通过KnockoutJs绑定显示。
  3. 将对应的分页信息绑定到Bootstrap分页中
  4. 当用户点击翻页时,再发起一个Ajax请求去异步调用Rest服务请求数据,再将请求的数据显示出来。

  这上面是描述的代码的调用逻辑关系,你可以参考对应的JS代码来理解上面的描述。到此我们第二种实现方式就实现完成了。

2.2 第一次加载所有数据,然后将所有数据分页显示

  接下来就介绍了第一种实现方式,这样的实现方式,用户只会在第一次的时候才会感觉到数据加载中,翻页过程中感觉不到页面的加载,这样对于一些本身数据了不是太多的情况下,对于用户的感觉也是更加流畅的。

  其具体的实现思路,也就是将请求的数据不要全部显示在页面上,因为数据太多,一下子显示到页面中,用户可能会眼花缭乱。将数据分页显示将使得用户查看更加清晰。

具体的Web前端Js的实现代码为:

var ListViewModel = function () {    var self = this;    window.viewModel = self;    self.list = ko.observableArray();    self.pageSize = ko.observable(3);     self.pageIndex = ko.observable(0); //要访问的页码    self.totalCount = ko.observable(1); //总记录数    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();   });

  其前端页面的实现与前面的实现类似。具体页面代码如下:

@{    ViewBag.Title = "Index";    Layout = "~/Views/Shared/_Layout.cshtml";}

任务列表

编号 名称 描述 负责人 创建时间 完成时间 状态
总共有
条记录, 每页显示:
View Code

三、运行效果

  接下来,让我们看看,使用KnockoutJs实现的分页效果:

 

四、总结

  到这里,本文要介绍的内容就结束,尽管本文实现的内容相对比较简单,但是对于一些刚接触KnockoutJs的朋友来说,相信本文的实现会是一个很多的指导。接下来,我将会为大家分享下AngularJs的相关内容。

本文所有源码实现:

 

转载地址:http://azrma.baihongyu.com/

你可能感兴趣的文章
彻底理解Javascript中的原型链与继承
查看>>
腾讯最大规模裁撤中层干部,让贤年轻人
查看>>
如何:强化 TCP/IP 堆栈安全
查看>>
Spring3 MVC中使用Swagger生成API文档
查看>>
FastCGI PHP on Windows Server 2003
查看>>
LimeSDR Getting Started Quickly | LimeSDR上手指南
查看>>
JSP标签JSTL的使用(1)--表达式操作
查看>>
SAP顾问的人脉比技术更为重要
查看>>
FI/CO PA考试试卷
查看>>
汽车介质应用非常严苛?没关系,新技术带来的高精度传感器十分适应!
查看>>
天合光能 - 用计算捕捉“光的能量”
查看>>
使用sysbench压力测试MySQL(一)(r11笔记第3天)
查看>>
css知多少(11)——position
查看>>
【Spring】定时任务详解实例-@Scheduled
查看>>
先有的资源,能看的速度看,不能看的,抽时间看。说不定那天就真的打不开了(转)...
查看>>
哪些领域适合开发微信小程序
查看>>
谁说数据库防火墙风险大?可能你还不知道应用关联防护
查看>>
ASP.NET Core应用针对静态文件请求的处理[2]: 条件请求与区间请求
查看>>
怎样做一个企业?尤其是在这个互联网时代
查看>>
DVNA:Node.js打造的开源攻防平台
查看>>