在前一篇,miniui datagrid 的客戶端分頁(yè)解決方案 中留下了一個(gè)問(wèn)題:如果前三頁(yè)只需要加載一次數(shù)據(jù),采用客戶端分頁(yè),之后的每一頁(yè)都仍然從服務(wù)器獲取,應(yīng)該怎么辦?
現(xiàn)在就來(lái)改造 ClientPagination
,讓它實(shí)現(xiàn)這個(gè)功能。不過(guò)在此之前需要先解決上個(gè)版本中存在的一個(gè)問(wèn)題:destroy()
并沒(méi)有完全恢復(fù)原有的 datagrid 對(duì)象,因?yàn)橥嗽?destroy()
中恢復(fù) this._datagrid
的 load
和 setData
函數(shù)。
很容易想到下面的代碼,不過(guò)下面這個(gè)代碼是個(gè)錯(cuò)誤的實(shí)現(xiàn)
destroy() {
// 錯(cuò)誤的實(shí)現(xiàn)
METHODS.forEach(name => {
this._datagrid[name] = this._origin[name];
});
// ....
}
別忘了 this._origin
中保存的每個(gè)函數(shù)都是通過(guò)原函數(shù) bind()
而來(lái),所以其實(shí)已經(jīng)不是原函數(shù)了。此外,也很容易想到 miniui 的 datagrid 多半是類實(shí)現(xiàn),原來(lái)的 load()
和 setData()
應(yīng)該來(lái)源于原型。所以正確的解決辦法是
// in destroy's body
METHODS.forEach(name => {
delete this._datagrid[name];
});
試驗(yàn)一下就能證明它的正確性。
原來(lái)在 beforeload
事件中直接設(shè)置了 event.cancel = true
來(lái)避免遠(yuǎn)程加載,但現(xiàn)在情況發(fā)生了變化,只需要在頁(yè)碼小于3(miniui 的 pageIndex
是從 0 開(kāi)始)避免遠(yuǎn)程加載,大于等于 3 的時(shí)候仍然需要從服務(wù)器獲取頁(yè)面數(shù)據(jù),所以
const pageIndex = e.data.pageIndex;
if (pageIndex < 3) {
e.cancel = true;
} else {
// 直接返回,不需要通過(guò) setPageData() 來(lái)設(shè)置頁(yè)面數(shù)據(jù)
return;
}
接下來(lái)還有一些細(xì)節(jié)需要處理。
首先就是 setData
中沒(méi)有使用數(shù)據(jù)的 total
值,因?yàn)樵瓉?lái)純客戶端分頁(yè)的時(shí)候,數(shù)據(jù)總行數(shù)就是 total
值,但現(xiàn)在不一樣了,設(shè)置的數(shù)據(jù)不一定是所有數(shù)據(jù),所以需要先檢查 total
,如果沒(méi)有 total
再使用 rows.length
代替。
setData(data) {
const rows = Array.isArray(data)
? data
: (data.data || []);
this._data = rows;
this._total = data.total || rows.length;
this.setPageData(this._datagrid.getPageIndex(), this._datagrid.getPageSize());
}
相應(yīng)的,還需要在 setPageData()
里修改一個(gè) setTotalCount()
的實(shí)參
grid.setTotalCount(this._total);
搞定!
mini_clientpagination.js
const METHODS = ["setData", "load"];
class ClientPagination {
static wrap(datagrid) {
return new ClientPagination(datagrid);
}
constructor(datagrid) {
this._datagrid = datagrid;
this._origin = {};
this.setup();
}
setup() {
const grid = this._datagrid;
const origin = this._origin = {};
METHODS.forEach(name => {
// 綁定到原對(duì)象的原方法
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() {
// 恢復(fù)原方法(來(lái)自 datagrid 類的 prototype)
// 只需要?jiǎng)h除附加到對(duì)象上的同名方法即可
METHODS.forEach(name => {
delete this._datagrid[name];
});
this._origin = {};
this._datagrid.un("beforeload", this._onBeforeLoad);
this._datagrid = null;
}
onBeforeLoad(e) {
// 根據(jù)官方的解決方案而來(lái)
const pageIndex = e.data.pageIndex;
if (pageIndex < 3) {
e.cancel = true;
} else {
// NOTE 一般來(lái)說(shuō)不需要修改 url,直接通過(guò) pageIndex 參數(shù)即可從后臺(tái)獲取不同頁(yè)的數(shù)據(jù)
// 這里因?yàn)槭怯玫撵o態(tài) JSON 數(shù)據(jù),所以需要修改 url
e.url = `data/page${pageIndex}.json`;
return;
}
let pageSize = e.data.pageSize;
this.setPageData(pageIndex, pageSize);
}
load(params, success, fail) {
const grid = this._datagrid;
const pageIndex = grid.getPageIndex();
const url = grid.getUrl();
params = $.extend(pageIndex < 3
? {}
: { pageIndex: pageIndex, pageSize: grid.getPageSize() },
params);
const settings = {
type: "get",
dataType: "json",
data: params
};
$.ajax(url, settings)
.then(data => {
this.setData(data);
if (typeof success === "function") {
success(data);
}
}, () => {
if (typeof fail === "function") {
fail();
}
});
}
setData(data) {
const rows = Array.isArray(data)
? data
: (data.data || []);
this._data = rows;
this._total = data.total || rows.length;
this.setPageData(this._datagrid.getPageIndex(), this._datagrid.getPageSize());
}
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(this._total);
grid.setPageIndex(pageIndex);
grid.setPageSize(pageSize);
this._origin.setData(pageData);
}
}
index.html
<!DOCTYPE html />
<html>
<head>
<title>Client Pagination</title>
<link href="miniui/themes/default/miniui.css" rel="stylesheet" type="text/css" />
<style type="text/css">
body {
margin: 0;
padding: 5px;
}
</style>
</head>
<body>
<div class="mini-fit">
<div class="mini-datagrid" id="grid" pageSize="6" url="data/all.json" style="height: 100%">
<div property="columns">
<div type="indexcolumn"></div>
<div type="checkboxcolumn" width="32"></div>
<div field="order" width="60">序號(hào)</div>
<div field="name" width="80">名稱</div>
<div field="autofit" width="auto"></div>
</div>
</div>
</div>
<script src="jquery-1.6.2.min.js"></script>
<script src="miniui/miniui.js"></script>
<script src="mini_clientpagination.js"></script>
<script>
mini.parse();
const grid = mini.get("grid");
ClientPagination.wrap(grid);
grid.load();
</script>
</body>
</html>
當(dāng)然還有 data 目錄下的數(shù)據(jù)源 all.json
和 page3.json
all.json 中是前3頁(yè)的數(shù)據(jù)
page3.json 中是第4頁(yè)的數(shù)據(jù)
數(shù)據(jù)結(jié)構(gòu)(僅結(jié)構(gòu)
{
"data": [],
"total": 50
}
其中 data
的每一項(xiàng)結(jié)構(gòu)
{
"order": 1108,
"name": "bridge"
}
完整的測(cè)試數(shù)據(jù)就自己拼吧,當(dāng)然最好是還是用服務(wù)端數(shù)據(jù),通過(guò)參數(shù)來(lái)返回不同的數(shù)據(jù)行。
我懶,懶得為了個(gè)實(shí)驗(yàn)還去寫服務(wù)端
更多建議: