miniui datagrid 的客戶端分頁解決方案

2018-06-09 10:42 更新

在前一篇,miniui datagrid 的客戶端分頁解決方案 中留下了一個問題:如果前三頁只需要加載一次數(shù)據(jù),采用客戶端分頁,之后的每一頁都仍然從服務(wù)器獲取,應(yīng)該怎么辦?

現(xiàn)在就來改造 ClientPagination,讓它實現(xiàn)這個功能。不過在此之前需要先解決上個版本中存在的一個問題:destroy() 并沒有完全恢復(fù)原有的 datagrid 對象,因為忘了在 destroy() 中恢復(fù) this._datagridloadsetData 函數(shù)。

修復(fù)一個重要的 BUG

很容易想到下面的代碼,不過下面這個代碼是個錯誤的實現(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];
        });

試驗一下就能證明它的正確性。

改造 ClientPagination

修改 beforeload 事件處理

原來在 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);

搞定!

源代碼

ClientPagination 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.jsonpage3.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ù)端

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號