在前一篇,miniui datagrid 的客戶端分頁解決方案 中留下了一個問題:如果前三頁只需要加載一次數(shù)據(jù),采用客戶端分頁,之后的每一頁都仍然從服務(wù)器獲取,應(yīng)該怎么辦?
現(xiàn)在就來改造 ClientPagination
,讓它實現(xiàn)這個功能。不過在此之前需要先解決上個版本中存在的一個問題:destroy()
并沒有完全恢復(fù)原有的 datagrid 對象,因為忘了在 destroy()
中恢復(fù) this._datagrid
的 load
和 setData
函數(shù)。
很容易想到下面的代碼,不過下面這個代碼是個錯誤的實現(xiàn)
destroy() {
// 錯誤的實現(xiàn)
METHODS.forEach(name => {
this._datagrid[name] = this._origin[name];
});
// ....
}
別忘了 this._origin
中保存的每個函數(shù)都是通過原函數(shù) bind()
而來,所以其實已經(jīng)不是原函數(shù)了。此外,也很容易想到 miniui 的 datagrid 多半是類實現(xiàn),原來的 load()
和 setData()
應(yīng)該來源于原型。所以正確的解決辦法是
// in destroy's body
METHODS.forEach(name => {
delete this._datagrid[name];
});
試驗一下就能證明它的正確性。
原來在 beforeload
事件中直接設(shè)置了 event.cancel = true
來避免遠程加載,但現(xiàn)在情況發(fā)生了變化,只需要在頁碼小于3(miniui 的 pageIndex
是從 0 開始)避免遠程加載,大于等于 3 的時候仍然需要從服務(wù)器獲取頁面數(shù)據(jù),所以
const pageIndex = e.data.pageIndex;
if (pageIndex < 3) {
e.cancel = true;
} else {
// 直接返回,不需要通過 setPageData() 來設(shè)置頁面數(shù)據(jù)
return;
}
接下來還有一些細節(jié)需要處理。
首先就是 setData
中沒有使用數(shù)據(jù)的 total
值,因為原來純客戶端分頁的時候,數(shù)據(jù)總行數(shù)就是 total
值,但現(xiàn)在不一樣了,設(shè)置的數(shù)據(jù)不一定是所有數(shù)據(jù),所以需要先檢查 total
,如果沒有 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()
里修改一個 setTotalCount()
的實參
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 => {
// 綁定到原對象的原方法
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ù)原方法(來自 datagrid 類的 prototype)
// 只需要刪除附加到對象上的同名方法即可
METHODS.forEach(name => {
delete this._datagrid[name];
});
this._origin = {};
this._datagrid.un("beforeload", this._onBeforeLoad);
this._datagrid = null;
}
onBeforeLoad(e) {
// 根據(jù)官方的解決方案而來
const pageIndex = e.data.pageIndex;
if (pageIndex < 3) {
e.cancel = true;
} else {
// NOTE 一般來說不需要修改 url,直接通過 pageIndex 參數(shù)即可從后臺獲取不同頁的數(shù)據(jù)
// 這里因為是用的靜態(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">序號</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>
當然還有 data 目錄下的數(shù)據(jù)源 all.json
和 page3.json
all.json 中是前3頁的數(shù)據(jù)
page3.json 中是第4頁的數(shù)據(jù)
數(shù)據(jù)結(jié)構(gòu)(僅結(jié)構(gòu)
{
"data": [],
"total": 50
}
其中 data
的每一項結(jié)構(gòu)
{
"order": 1108,
"name": "bridge"
}
完整的測試數(shù)據(jù)就自己拼吧,當然最好是還是用服務(wù)端數(shù)據(jù),通過參數(shù)來返回不同的數(shù)據(jù)行。
我懶,懶得為了個實驗還去寫服務(wù)端
更多建議: