miniui datagrid的客户端分页解决方案

开发 前端
首先,是绑定一个 preload 事件,在这个事情中设置 event.cancel = true,阻止 datagrid 在翻页的时候向服务器请求加载数据。那么数据从哪来呢?当然只有在外部写一个 ajax 过程获取了。不过取得的数据并不直接交给 datagrid,而是缓存起来,放在 dataResult 中。

[[174396]]

官方的解决方案

官方在“在线示例”中给了一个简单的 client pagination 解决方案,代码就不贴了,这里说说它的基本思想和处理过程。

首先,是绑定一个 preload 事件,在这个事情中设置 event.cancel = true,阻止 datagrid 在翻页的时候向服务器请求加载数据。

那么数据从哪来呢?当然只有在外部写一个 ajax 过程获取了。不过取得的数据并不直接交给 datagrid,而是缓存起来,放在dataResult 中。

现在继续说 preload,除了阻止 datagrid 向服务器请求数据之外,preload 还需要从缓存中找到页码对应的数据行,通过 setData设置给 datagrid 渲染出来。OK,这个事情是交给自定义函数 fillData 来实现的。当然,这里还要干点与页面相关的事情,就是setTotalCount()、setPageIndex() 和 setPageCount()。

官方的解决方案展示了 miniui datagrid 客户端分页解决方案的基本思想,但是这个示例太过简单。如果,想把之前的服务端分页改成客户端分页该怎么办?原来已经存在对 load()、setData() 等的调用,现在怎样以最小的代码改动来实现客户端分页?

class ClientPagination

就上面的问题,首先能想到的,就是保留原有 load() 和 setData() 的接口,但是要改变它们的行为。

  • load() 原有行为是提交了〔XXX参数〕,从服务器加载指定页的数据;而现在需要改为加载所有数据。
  • setData() 原来是向 datagrid 设置了需要显示的所有数据行,不管分页(比如可以一次显示出来200条数据);而现在,如果设置的数据量过大,则需要通过客户端分页来逐页显示。

JavaScript 语言是动态有,这使得替换方法成为可能,这是很多静态语言做不到的事情。而替换方法也是解决这个问题时最容易想到的办法。当然除此之外,还得庆幸 miniui 没有采用 jQuery 扩展的方式(如 $grid.datagrid("setData", ...))来实现组件。

替换方法成为可能,但是原有方法还是得保留,因为我们需要通过原有方法来操作 datagrid。所以 ClientPagination 类应该是这个样子:

ClientPagination 的基本结构

注:本文中所有代码都是 ES6 语法 

  1. const METHODS = ["setData""load"]; 
  2.  
  3. class ClientPagination { 
  4.     constructor(datagrid) { 
  5.         this._datagrid = datagrid; 
  6.         this._origin = {}; 
  7.         this.setup(); 
  8.     } 
  9.      
  10.     setup() { 
  11.         // TODO 暂存 this._datagrid 的 load、setData 等方法 
  12.         // 并为 this._datagrid 设置新方法和注册事件 
  13.     } 
  14.  
  15.     destroy() { 
  16.         // TODO 恢复 this._datagrid 的方法,注销事件 
  17.     } 
  18.      
  19.     onBeforeLoad() { 
  20.         // 根据官方的解决方案而来 
  21.         e.cancel = true
  22.         let pageIndex = e.data.pageIndex; 
  23.         let pageSize = e.data.pageSize; 
  24.         this.setPageData(pageIndex, pageSize); 
  25.     } 
  26.  
  27.     // 参照 datagrid.load 的函数签名 
  28.     load(params, success, fail) { 
  29.         // TODO 实现加载数据,并保存到 this._data 中 
  30.         // 然后调用 this.setData() 保存和显示数据 
  31.     } 
  32.  
  33.     setData(data) { 
  34.         // TODO 保存 data 到 this._data 中, 
  35.         // 然后调用 this.setPageData() 显示当前页的数据 
  36.     } 
  37.      
  38.     setPageData(pageIndex, pageSize) { 
  39.         // TODO 从缓存的 this._data 中按 pageIndex 和 pageSize 取出要显示的数据行 
  40.         // 然后通过 this._origin.setData() 设置在 datagrid 中 
  41.     } 
  42.  

设置和解除客户端分页

其中 setup 和 destroy 为分别为 datagrid 绑定和解绑客户端分页处理

  1. setup() { 
  2.        const grid = this._datagrid; 
  3.        const original = this._origin = {}; 
  4.  
  5.        METHODS.forEach(name => { 
  6.            // 暂存原方法 
  7.            origin[name] = grid[name].bind(grid); 
  8.            // 替换为本类中定义的新方法 
  9.            grid[name] = this[name].bind(this); 
  10.        }); 
  11.  
  12.        // 暂存事件处理函数,以便后面注销 
  13.        this._onBeforeLoad = this.onBeforeLoad.bind(this); 
  14.        grid.on("beforeload", this._onBeforeLoad); 
  15.    } 
  16.  
  17.    destroy() { 
  18.        this._origin = {}; 
  19.        this._datagrid.un("beforeload", this._onBeforeLoad); 
  20.        this._datagrid = null
  21.    }  

来自官方示例中的关键代码

onBeforeLoad 以及 setPageData 是参照官方解决方案中的 beforeload 事件和 fillData 方法写的。onBeforeLoad 的代码在上面已经有了,现在是 setPageData 的代码

  1. setPageData(pageIndex, pageSize) { 
  2.         const allData = this._data; 
  3.         let start = pageIndex * pageSize; 
  4.         if (start >= allData.length) { 
  5.             start = 0; 
  6.             pageIndex = 0; 
  7.         } 
  8.         const end = Math.min(start + pageSize, allData.length); 
  9.  
  10.         const pageData = []; 
  11.         for (let i = start; i < end; i++) { 
  12.             pageData.push(allData[i]); 
  13.         } 
  14.  
  15.         const grid = this._datagrid; 
  16.         grid.setTotalCount(allData.length); 
  17.         grid.setPageIndex(pageIndex); 
  18.         grid.setPageSize(pageSize); 
  19.         this._origin.setData(pageData); 
  20.     }  

改写 load

load 方法需要用 ajax 调用来替换原来的 load 方法 

  1. load(params, success, fail) { 
  2.         const grid = this._datagrid; 
  3.         const url = grid.getUrl(); 
  4.  
  5.         const settings = { 
  6.             type: "post"
  7.             dataType: "json"
  8.             data: params || {} 
  9.         }; 
  10.  
  11.         $.ajax(url, settings) 
  12.             .then(data => { 
  13.                 this.setData(data); 
  14.                 if (typeof success === "function") { 
  15.                     success(data); 
  16.                 } 
  17.             }, () => { 
  18.                 if (typeof fail === "function") { 
  19.                     fail(); 
  20.                 } 
  21.             }); 
  22.     }  

改写 setData

而 setData 也进行了替换,参数是整表的数据,但只能显示当前页的数据

  1. setData(data) { 
  2.         const rows = Array.isArray(data) 
  3.             ? data 
  4.             : (data.data || []); 
  5.  
  6.         this._data = rows
  7.         this.setPageData(this._datagrid.getPageIndex(), this._datagrid.getPageSize()); 
  8.     }  

应用

为了方便封装,再加一个静态方法

  1. static wrap(datagrid) { 
  2.         return new ClientPagination(datagrid); 
  3.     }  

现在只需要在页面初始化(或其它合适的初始化位置)加上

  1. ClientPagination.wrap(mini.get("datagridId")); 

如果需要 destroy,可以这样

  1. var cpBlabla = ClientPagination.wrap(mini.get("datagridId")); 
  2. .... 
  3. cpBalbal.destory();  

小结

通过 ClientPagination 的封装,不需要改变原有的业务代码和设置,就可以实现 miniui datagrid 的客户端分页。

但是这个实现只是解决了当前的问题,如果有新的需求:

当页码在前三页的时候用客户端分页,以减少数据加载次数,翻到后面的时候需要用服务器端分页

责任编辑:庞桂玉 来源: segmentfault
相关推荐

2013-05-30 17:52:06

2019-09-08 16:45:19

JavaScriptHTML5GitHub

2012-12-18 09:34:49

2014-06-18 10:25:31

戴尔

2009-12-30 15:29:14

2014-08-01 18:26:49

戴尔

2021-10-04 09:14:18

ElasticSear深度分页

2021-09-22 15:46:29

虚拟桌面瘦客户端胖客户端

2012-09-04 09:40:01

2011-06-08 22:06:04

工作站解决方案

2010-03-17 18:04:55

java Socket

2010-08-06 14:13:31

FlexDataGrid分页控

2011-04-06 14:24:20

Nagios监控Linux

2011-03-21 14:53:36

Nagios监控Linux

2011-08-17 10:10:59

2009-11-05 13:08:44

WCF客户端配置

2010-05-31 10:11:32

瘦客户端

2011-03-24 13:00:31

配置nagios客户端

2010-12-21 11:03:15

获取客户端证书

2011-03-02 14:36:24

Filezilla客户端
点赞
收藏

51CTO技术栈公众号