官方在“在線示例”中給了一個簡單的 client pagination 解決方案,代碼就不貼了,這里說說它的基本思想和處理過程。
首先,是綁定一個 preload
事件,在這個事情中設(shè)置 event.cancel = true
,阻止 datagrid 在翻頁的時候向服務(wù)器請求加載數(shù)據(jù)。
那么數(shù)據(jù)從哪來呢?當然只有在外部寫一個 ajax 過程獲取了。不過取得的數(shù)據(jù)并不直接交給 datagrid,而是緩存起來,放在 dataResult
中。
現(xiàn)在繼續(xù)說 preload
,除了阻止 datagrid 向服務(wù)器請求數(shù)據(jù)之外,preload
還需要從緩存中找到頁碼對應(yīng)的數(shù)據(jù)行,通過 setData
設(shè)置給 datagrid 渲染出來。OK,這個事情是交給自定義函數(shù) fillData
來實現(xiàn)的。當然,這里還要干點與頁面相關(guān)的事情,就是 setTotalCount()
、setPageIndex()
和 setPageCount()
。
官方的解決方案展示了 miniui datagrid 客戶端分頁解決方案的基本思想,但是這個示例太過簡單。如果,想把之前的服務(wù)端分頁改成客戶端分頁該怎么辦?原來已經(jīng)存在對 load()
、setData()
等的調(diào)用,現(xiàn)在怎樣以最小的代碼改動來實現(xiàn)客戶端分頁?
就上面的問題,首先能想到的,就是保留原有 load()
和 setData()
的接口,但是要改變它們的行為。
load()
原有行為是提交了〔XXX參數(shù)〕,從服務(wù)器加載指定頁的數(shù)據(jù);而現(xiàn)在需要改為加載所有數(shù)據(jù)。
setData()
原來是向 datagrid 設(shè)置了需要顯示的所有數(shù)據(jù)行,不管分頁(比如可以一次顯示出來200條數(shù)據(jù));而現(xiàn)在,如果設(shè)置的數(shù)據(jù)量過大,則需要通過客戶端分頁來逐頁顯示。
JavaScript 語言是動態(tài)有,這使得替換方法成為可能,這是很多靜態(tài)語言做不到的事情。而替換方法也是解決這個問題時最容易想到的辦法。當然除此之外,還得慶幸 miniui 沒有采用 jQuery 擴展的方式(如 $grid.datagrid("setData", ...)
)來實現(xiàn)組件。
替換方法成為可能,但是原有方法還是得保留,因為我們需要通過原有方法來操作 datagrid。所以 ClientPagination
類應(yīng)該是這個樣子:
注:本文中所有代碼都是 ES6 語法
const METHODS = ["setData", "load"];
class ClientPagination {
constructor(datagrid) {
this._datagrid = datagrid;
this._origin = {};
this.setup();
}
setup() {
// TODO 暫存 this._datagrid 的 load、setData 等方法
// 并為 this._datagrid 設(shè)置新方法和注冊事件
}
destroy() {
// TODO 恢復 this._datagrid 的方法,注銷事件
}
onBeforeLoad() {
// 根據(jù)官方的解決方案而來
e.cancel = true;
let pageIndex = e.data.pageIndex;
let pageSize = e.data.pageSize;
this.setPageData(pageIndex, pageSize);
}
// 參照 datagrid.load 的函數(shù)簽名
load(params, success, fail) {
// TODO 實現(xiàn)加載數(shù)據(jù),并保存到 this._data 中
// 然后調(diào)用 this.setData() 保存和顯示數(shù)據(jù)
}
setData(data) {
// TODO 保存 data 到 this._data 中,
// 然后調(diào)用 this.setPageData() 顯示當前頁的數(shù)據(jù)
}
setPageData(pageIndex, pageSize) {
// TODO 從緩存的 this._data 中按 pageIndex 和 pageSize 取出要顯示的數(shù)據(jù)行
// 然后通過 this._origin.setData() 設(shè)置在 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);
});
// 暫存事件處理函數(shù),以便后面注銷
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
的代碼在上面已經(jīng)有了,現(xiàn)在是 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
方法需要用 ajax 調(diào)用來替換原來的 load
方法
load(params, success, fail) {
const grid = this._datagrid;
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
也進行了替換,參數(shù)是整表的數(shù)據(jù),但只能顯示當前頁的數(shù)據(jù)
setData(data) {
const rows = Array.isArray(data)
? data
: (data.data || []);
this._data = rows;
this.setPageData(this._datagrid.getPageIndex(), this._datagrid.getPageSize());
}
為了方便封裝,再加一個靜態(tài)方法
static wrap(datagrid) {
return new ClientPagination(datagrid);
}
現(xiàn)在只需要在頁面初始化(或其它合適的初始化位置)加上
ClientPagination.wrap(mini.get("datagridId"));
如果需要 destroy
,可以這樣
var cpBlabla = ClientPagination.wrap(mini.get("datagridId"));
....
cpBalbal.destory();
通過 ClientPagination 的封裝,不需要改變原有的業(yè)務(wù)代碼和設(shè)置,就可以實現(xiàn) miniui datagrid 的客戶端分頁。
但是這個實現(xiàn)只是解決了當前的問題,如果有新的需求:
當頁碼在前三頁的時候用客戶端分頁,以減少數(shù)據(jù)加載次數(shù),翻到后面的時候需要用服務(wù)器端分頁
又該如何?是不是該出個續(xù)集?
更多建議: