天天看点

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

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

官方的解决方案

官方在“在线示例”中给了一个简单的 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 语法

const methods = ["setdata", "load"]; 

class clientpagination { 

    constructor(datagrid) { 

        this._datagrid = datagrid; 

        this._origin = {}; 

        this.setup(); 

    } 

    setup() { 

        // todo 暂存 this._datagrid 的 load、setdata 等方法 

        // 并为 this._datagrid 设置新方法和注册事件 

    destroy() { 

        // todo 恢复 this._datagrid 的方法,注销事件 

    onbeforeload() { 

        // 根据官方的解决方案而来 

        e.cancel = true; 

        let pageindex = e.data.pageindex; 

        let pagesize = e.data.pagesize; 

        this.setpagedata(pageindex, pagesize); 

    // 参照 datagrid.load 的函数签名 

    load(params, success, fail) { 

        // todo 实现加载数据,并保存到 this._data 中 

        // 然后调用 this.setdata() 保存和显示数据 

    setdata(data) { 

        // todo 保存 data 到 this._data 中, 

        // 然后调用 this.setpagedata() 显示当前页的数据 

    setpagedata(pageindex, pagesize) { 

        // todo 从缓存的 this._data 中按 pageindex 和 pagesize 取出要显示的数据行 

        // 然后通过 this._origin.setdata() 设置在 datagrid 中 

}  

设置和解除客户端分页

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

setup() { 

       const grid = this._datagrid; 

       const original = this._origin = {}; 

       methods.foreach(name => { 

           // 暂存原方法 

           origin[name] = grid[name].bind(grid); 

           // 替换为本类中定义的新方法 

           grid[name] = this[name].bind(this); 

       }); 

       // 暂存事件处理函数,以便后面注销 

       this._onbeforeload = this.onbeforeload.bind(this); 

       grid.on("beforeload", this._onbeforeload); 

   } 

   destroy() { 

       this._origin = {}; 

       this._datagrid.un("beforeload", this._onbeforeload); 

       this._datagrid = null; 

   }  

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

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

setpagedata(pageindex, pagesize) { 

        const alldata = this._data; 

        let start = pageindex * pagesize; 

        if (start >= alldata.length) { 

            start = 0; 

            pageindex = 0; 

        } 

        const end = math.min(start + pagesize, alldata.length); 

        const pagedata = []; 

        for (let i = start; i < end; i++) { 

            pagedata.push(alldata[i]); 

        const grid = this._datagrid; 

        grid.settotalcount(alldata.length); 

        grid.setpageindex(pageindex); 

        grid.setpagesize(pagesize); 

        this._origin.setdata(pagedata); 

    }  

改写 load

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

load(params, success, fail) { 

        const url = grid.geturl(); 

        const settings = { 

            type: "post", 

            datatype: "json", 

            data: params || {} 

        }; 

        $.ajax(url, settings) 

            .then(data => { 

                this.setdata(data); 

                if (typeof success === "function") { 

                    success(data); 

                } 

            }, () => { 

                if (typeof fail === "function") { 

                    fail(); 

            }); 

改写 setdata

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

setdata(data) { 

        const rows = array.isarray(data) 

            ? data 

            : (data.data || []); 

        this._data = rows; 

        this.setpagedata(this._datagrid.getpageindex(), this._datagrid.getpagesize()); 

应用

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

static wrap(datagrid) { 

        return new clientpagination(datagrid); 

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

clientpagination.wrap(mini.get("datagridid")); 

如果需要 destroy,可以这样

var cpblabla = clientpagination.wrap(mini.get("datagridid")); 

.... 

cpbalbal.destory();  

小结

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

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

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

作者:边城

来源:51cto

继续阅读