Extjs TreeStore+pagingToolbar 分页

Extjs很强大,但也很庞大,还有一些地方不满足一些需求,变态需求就另说了。
       在4中Tree不带有分页,为了满足需求,只能扩展Ext的组件。
       仔细看TreeStore中源码,可以对比着Store中的源码,其实TreeStore中只是缺少了分页参数,以及对这些参数的逻辑和封装。我们只需要传入参数,加入分页逻辑,并封装起来。
       思路有了,就按着需求写。

 

 

 

 

/**

 * Extjs4.1 TreeStore 分页 

 * 

 * @作者:徐盛

 * @日期:2012-10-23

 * @用法:

 * Ext.create('APP.plugin.TreeStore', {

 * model: 'myModel',

 * storeId: 'MyTreeModel',

 * proxy: {

 * type: 'ajax',

 * url: 'url.do',

 * reader: {

 * type: 'json',

 * root: 'myTree',

 * totalProperty: 'totalProperty' // 一定需要这个参数接受后台返回的总条数 

 * }

 * },

 * root: {

 * id: 0,

 * text: 'root',

 * expanded: true

 * }

 * })

 *    

 *   其余都一样,主要是totalProperty,这个返回总条数

 *

 * @说明:

 * 目前只能实现root节点下的分页。

 *     在原Extjs4.1 TreeStore中加入的分页所需参数。

 * 如不满足需求,需自行调试加入方法。

 *      联系QQ:78264486

 *

 */

Ext.define('APP.plugin.TreeStore', {

extend: 'Ext.data.TreeStore',

alias: 'store.MyTreeStore',

/**

* 每页显示条数

*

*/

pageSize: undefined,

/**

* 当前页 默认为第一页

*

*/

currentPage: 1,

purgePageCount: 5,

defaultPageSize: 25,

/**

* 构造函数

*

*/

constructor: function(config) {

        var me = this,

            root,

            fields,

            defaultRoot,

data,

proxy;

 

        config = Ext.apply({}, config);

/**

         * @event prefetch

         * Fires whenever records have been prefetched

         * @param {Ext.data.Store} this

         * @param {Ext.data.Model[]} records An array of records.

         * @param {Boolean} successful True if the operation was successful.

         * @param {Ext.data.Operation} operation The associated operation

         */

        data = config.data || me.data;

 

        /**

         * @property {Ext.util.MixedCollection} data

         * The MixedCollection that holds this store's local cache of records.

         */

        me.data = new Ext.util.MixedCollection(false, Ext.data.Store.recordIdFn);

if (data) {

            me.inlineData = data;

            delete config.data;

        }

 

        /**

         * If we have no fields declare for the store, add some defaults.

         * These will be ignored if a model is explicitly specified.

         */

        fields = config.fields || me.fields;

        if (!fields) {

            config.fields = [

                {name: 'text', type: 'string'}

            ];

            defaultRoot = config.defaultRootProperty || me.defaultRootProperty;

            if (defaultRoot !== me.defaultRootProperty) {

                config.fields.push({

                    name: defaultRoot,   

                    type: 'auto',   

                    defaultValue: null, 

                    persist: false

                });

            }

        }

 

        me.callParent([config]);

/**

* @property {Ext.data.Store.PageMap} pageMap

* Internal PageMap instance.

* @private

*/

me.pageMap = new me.PageMap({

pageSize: me.pageSize,

maxSize: me.purgePageCount,

listeners: {

// Whenever PageMap gets cleared, it means we re no longer interested in 

// any outstanding page prefetches, so cancel tham all

clear: me.cancelAllPrefetches,

scope: me

}

});

me.pageRequests = {};

me.sortOnLoad = false;

me.filterOnLoad = false;

proxy = me.proxy;

        data = me.inlineData;

if (data) {

            if (proxy instanceof Ext.data.proxy.Memory) {

                proxy.data = data;

                me.read();

            } else {

                me.add.apply(me, [data]);

            }

 

            me.sort();

            delete me.inlineData;

        } else if (me.autoLoad) {

            Ext.defer(me.load, 10, me, [ typeof me.autoLoad === 'object' ? me.autoLoad : undefined ]);

            // Remove the defer call, we may need reinstate this at some point, but currently it's not obvious why it's here.

            // this.load(typeof this.autoLoad == 'object' ? this.autoLoad : undefined);

        }

        // We create our data tree.

        me.tree = new Ext.data.Tree();

 

        me.relayEvents(me.tree, [

            /**

             * @event append

             * @inheritdoc Ext.data.Tree#append

             */

            "append",

 

            /**

             * @event remove

             * @inheritdoc Ext.data.Tree#remove

             */

            "remove",

 

            /**

             * @event move

             * @inheritdoc Ext.data.Tree#move

             */

            "move",

 

            /**

             * @event insert

             * @inheritdoc Ext.data.Tree#insert

             */

            "insert",

 

            /**

             * @event beforeappend

             * @inheritdoc Ext.data.Tree#beforeappend

             */

            "beforeappend",

 

            /**

             * @event beforeremove

             * @inheritdoc Ext.data.Tree#beforeremove

             */

            "beforeremove",

 

            /**

             * @event beforemove

             * @inheritdoc Ext.data.Tree#beforemove

             */

            "beforemove",

 

            /**

             * @event beforeinsert

             * @inheritdoc Ext.data.Tree#beforeinsert

             */

            "beforeinsert",

 

            /**

             * @event expand

             * @inheritdoc Ext.data.Tree#expand

             */

            "expand",

 

            /**

             * @event collapse

             * @inheritdoc Ext.data.Tree#collapse

             */

            "collapse",

 

            /**

             * @event beforeexpand

             * @inheritdoc Ext.data.Tree#beforeexpand

             */

            "beforeexpand",

 

            /**

             * @event beforecollapse

             * @inheritdoc Ext.data.Tree#beforecollapse

             */

            "beforecollapse",

 

            /**

             * @event sort

             * @inheritdoc Ext.data.Tree#sort

             */

            "sort",

 

            /**

             * @event rootchange

             * @inheritdoc Ext.data.Tree#rootchange

             */

            "rootchange"

        ]);

 

        me.tree.on({

            scope: me,

            remove: me.onNodeRemove,

            // this event must follow the relay to beforeitemexpand to allow users to

            // cancel the expand:

            beforeexpand: me.onBeforeNodeExpand,

            beforecollapse: me.onBeforeNodeCollapse,

            append: me.onNodeAdded,

            insert: me.onNodeAdded,

            sort: me.onNodeSort

        });

 

        me.onBeforeSort();

 

        root = me.root;

        if (root) {

            delete me.root;

            me.setRootNode(root);

        }

 

        //<deprecated since=0.99>

        if (Ext.isDefined(me.nodeParameter)) {

            if (Ext.isDefined(Ext.global.console)) {

                Ext.global.console.warn('Ext.data.TreeStore: nodeParameter has been deprecated. Please use nodeParam instead.');

            }

            me.nodeParam = me.nodeParameter;

            delete me.nodeParameter;

        }

        //</deprecated>

    },

/**

     * Loads the Store using its configured {@link #proxy}.

     * @param {Object} options (Optional) config object. This is passed into the {@link Ext.data.Operation Operation}

     * object that is created and then sent to the proxy's {@link Ext.data.proxy.Proxy#read} function.

     * The options can also contain a node, which indicates which node is to be loaded. If not specified, it will

     * default to the root node.

     */

    load: function(options) {

        options = options || {};

        options.params = options.params || {};

 

        var me = this,

            node = options.node || me.tree.getRootNode();

options.page = options.page || me.currentPage;

        options.start = (options.start !== undefined) ? options.start : (options.page - 1) * me.pageSize;

        options.limit = options.limit || me.pageSize;

 

        // If there is not a node it means the user hasnt defined a rootnode yet. In this case lets just

        // create one for them.

        if (!node) {

            node = me.setRootNode({

                expanded: true

            }, true);

        }

 

        // Assign the ID of the Operation so that a REST proxy can create the correct URL

        options.id = node.getId();

 

        if (me.clearOnLoad) {

            if(me.clearRemovedOnLoad) {

                // clear from the removed array any nodes that were descendants of the node being reloaded so that they do not get saved on next sync.

                me.clearRemoved(node);

            }

            // temporarily remove the onNodeRemove event listener so that when removeAll is called, the removed nodes do not get added to the removed array

            me.tree.un('remove', me.onNodeRemove, me);

            // remove all the nodes

            node.removeAll(false);

            // reattach the onNodeRemove listener

            me.tree.on('remove', me.onNodeRemove, me);

        }

 

        Ext.applyIf(options, {

            node: node

        });

        options.params[me.nodeParam] = node ? node.getId() : 'root';

 

        if (node) {

            node.set('loading', true);

        }

 

        return me.callParent([options]);

    },

// inherit docs

    onProxyLoad: function(operation) {

        var me = this,

            successful = operation.wasSuccessful(),

            records = operation.getRecords(),

            node = operation.node,

resultSet = operation.getResultSet();

if (resultSet) {

me.totalCount = resultSet.total;

}

me.mycount = resultSet.count;

 

        me.loading = false;

        node.set('loading', false);

        if (successful) {

            if (!me.clearOnLoad) {

                records = me.cleanRecords(node, records);

            }

            records = me.fillNode(node, records);

        }

        // The load event has an extra node parameter

        // (differing from the load event described in AbstractStore)

        /**

         * @event load

         * Fires whenever the store reads data from a remote data source.

         * @param {Ext.data.TreeStore} this

         * @param {Ext.data.NodeInterface} node The node that was loaded.

         * @param {Ext.data.Model[]} records An array of records.

         * @param {Boolean} successful True if the operation was successful.

         */

        // deprecate read?

        me.fireEvent('read', me, operation.node, records, successful);

        me.fireEvent('load', me, operation.node, records, successful);

        //this is a callback that would have been passed to the 'read' function and is optional

        Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);

    },

/**

* 获取总条数

*

*/

getTotalCount: function() {

        return this.totalCount || 0;

    },

/**

* 获取当前data中条目数

*

*/

getCount: function () {

return this.mycount || 0;

},

/**

     * Loads a given 'page' of data by setting the start and limit values appropriately. Internally this just causes a normal

     * load operation, passing in calculated 'start' and 'limit' params

     * @param {Number} page The number of the page to load

     * @param {Object} options See options for {@link #method-load}

     */

loadPage: function(page, options) {

        var me = this;

 

        me.currentPage = page;

 

        // Copy options into a new object so as not to mutate passed in objects

        options = Ext.apply({

            page: page,

            start: (page - 1) * me.pageSize,

            limit: me.pageSize,

            addRecords: !me.clearOnPageLoad

        }, options);

 

        if (me.buffered) {

            return me.loadToPrefetch(options);

        }

        me.read(options);

    },

/**

     * Loads the next 'page' in the current data set

     * @param {Object} options See options for {@link #method-load}

     */

    nextPage: function(options) {

        this.loadPage(this.currentPage + 1, options);

    },

 

    /**

     * Loads the previous 'page' in the current data set

     * @param {Object} options See options for {@link #method-load}

     */

    previousPage: function(options) {

        this.loadPage(this.currentPage - 1, options);

    },

/**

     * @private

     * Cancels all pending prefetch requests.

     *

     * This is called when the page map is cleared.

     *

     * Any requests which still make it through will be for the previous page map generation

     * (generation is incremented upon clear), and so will be rejected upon arrival.

     */

    cancelAllPrefetches: function() {

        var me = this,

            reqs = me.pageRequests,

            req,

            page;

 

        // If any requests return, we no longer respond to them.

        if (me.pageMap.events.pageadded) {

            me.pageMap.events.pageadded.clearListeners();

        }

 

        // Cancel all outstanding requests

        for (page in reqs) {

            if (reqs.hasOwnProperty(page)) {

                req = reqs[page];

                delete reqs[page];

                delete req.callback;

            }

        }

    },

/**

* 根据树JSON 中id 获取对应NODE

*

* 此方法会调用Ext.data.Tree中的getNodeById

*

*/

getNodeById: function (id) {

return this.tree.getNodeById(id);

}

}, function() {

    var proto = this.prototype;

    proto.indexSorter = new Ext.util.Sorter({

        sorterFn: proto.sortByIndex

    });

 

    /**

     * @class Ext.data.Store.PageMap

     * @extends Ext.util.LruCache

     * Private class for use by only Store when configured `buffered: true`.

     * @private

     */

    this.prototype.PageMap = new Ext.Class({

        extend: 'Ext.util.LruCache',

 

        // Maintain a generation counter, so that the Store can reject incoming pages destined for the previous generation

        clear: function(initial) {

            this.generation = (this.generation ||0) + 1;

            this.callParent(arguments);

        },

 

        getPageFromRecordIndex: this.prototype.getPageFromRecordIndex,

 

        addPage: function(page, records) {

            this.add(page, records);

            this.fireEvent('pageAdded', page, records);

        },

 

        getPage: function(page) {

            return this.get(page);

        },

 

        hasRange: function(start, end) {

            var page = this.getPageFromRecordIndex(start),

                endPage = this.getPageFromRecordIndex(end);

 

            for (; page <= endPage; page++) {

                if (!this.hasPage(page)) {

                    return false;

                }

            }

            return true;

        },

 

        hasPage: function(page) {

            // We must use this.get to trigger an access so that the page which is checked for presence is not eligible for pruning

            return !!this.get(page);

        },

 

        getRange: function(start, end) {

            if (!this.hasRange(start, end)) {

                Ext.Error.raise('PageMap asked for range which it does not have');

            }

            var me = this,

                startPage = me.getPageFromRecordIndex(start),

                endPage = me.getPageFromRecordIndex(end),

                dataStart = (startPage - 1) * me.pageSize,

                dataEnd = (endPage * me.pageSize) - 1,

                page = startPage,

                result = [],

                sliceBegin, sliceEnd, doSlice,

                i = 0, len;

 

            for (; page <= endPage; page++) {

 

                // First and last pages will need slicing to cut into the actual wanted records

                if (page == startPage) {

                    sliceBegin = start - dataStart;

                    doSlice = true;

                } else {

                    sliceBegin = 0;

                    doSlice = false;

                }

                if (page == endPage) {

                    sliceEnd = me.pageSize - (dataEnd - end);

                    doSlice = true;

                }

 

                // First and last pages will need slicing

                if (doSlice) {

                    Ext.Array.push(result, Ext.Array.slice(me.getPage(page), sliceBegin, sliceEnd));

                } else {

                    Ext.Array.push(result, me.getPage(page));

                }

            }

 

            // Inject the dataset ordinal position into the record as the index

            for (len = result.length; i < len; i++) {

                result[i].index = start++;

            }

            return result;

        }

    });

});

你可能感兴趣的:(分页,ExtJs,extjs4,TreeStore,pagingtoolbar)