日期:2014-05-16  浏览次数:20355 次

ExtJs的TreePanel的分页的思路和实现

Ext的Tree组件很好用,但是当节点多的时候,加载会很慢,如果能够带上分页的话,那就很好了,于是我想对Tree组件进行扩展,使之能够实现分页,这样就可以解决节点多的时候,页面加载速度的问题了

?

我的分页思路比较简单,就是对最顶层的根节点进行分页,也就是root节点,通过前台传过去的分页参数,在后台将数据按页读取出来,然后再前台的根节点下面展现出来,来实现分页的效果,至于后来的分页如何实现,就不在本文章的讨论范围内。本文章只讨论前台的展现。

?

实现思路:

由于Tree组件是通过TreePanel来展现的,而TreePanel有个bbar属性,可以放PagingToolbar对象,因此我们可以把分页组件树页面展现出来了,但是PagingToolbar的分页是需要通过Store来支持的,而我们的Tree组件是没有Store,只有loder,因此主要的着手点就在于构造一个可以让PagingToolbar分页时可以识别,并且能够自动调用loader获取节点的Store就可以,因为tree组件的laod方法,可以读取出节点,并展现成熟,因此只要store在load的时候,能够把节点load出来就可以,所以基本的做法就是在Store的load方法中调用tree组件的loader的load方法获取节点并展现,这是把需要分页的参数传到后来即可。思路是挺简单的,接下来看看实现的代码

?

/**
 * 树分页数据源加载器,只对最顶层根节点进行分页,这意味着,子节点的节点数目不能太多,否则会有性能问题
 * @class Ext.tree.TreeLoaderStore
 * @extends Ext.data.Store
 */
Ext.tree.TreeLoaderStore = Ext.extend(Ext.data.Store,{
	/**
	 * 加载数据源的数据对象,是树结构的loader
	 * @type  Ext.tree.TreePagingLoader
	 */
	loader:null,
	/**
	 * 树的根节点,最顶的节点
	 * @type Ext.tree.AsyncTreeNode
	 */
	rootNode:null,
	constructor : function(config){
	 	Ext.tree.TreeLoaderStore.superclass.constructor.call(this);
	 	this.loader = config.loader;
	 	this.rootNode = config.rootNode;
	 },
	 load:function(options){
	 	var _self = this;
	 	if(!this.loader || !this.rootNode){
	 		Ext.MessageBox.alert("错误","必须指定loader或者rootNode");
	 		return false;
	 	}
	 	Ext.apply(this.loader.baseParams,{start:options.params.start,limit:options.params.limit}),
	 	this.loader.load(this.rootNode,function(node){
	 		_self.currentCount = _self.loader.currentCount;
	 		_self.totalLength = _self.loader.totalCount;
	 		node.expand();
	 		_self.fireEvent("load",_self,null,options);
	 		delete _self;
	 	});
	 	return true;
	 },
	 getCount : function(){
        return this.currentCount || 0;
     },
     getTotalCount : function(){
        return this.totalLength || 0;
    }
})

Ext.tree.TreePagingLoader = Ext.extend(Ext.tree.TreeLoader,{
    processResponse : function(response, node, callback, scope){
        var json = response.responseText;
        try {
            var o = response.responseData || Ext.decode(json);
            //TODO:暂时从后台获取当前页的记录数,通过currentCount属性获取
            //最佳做法是效仿pagingToolbar的做法,在客户端获取
            //目前的障碍是,loader还没读取完,翻页的工具栏已经初始化了,导致当前页记录数无法获取
            //有空再继续修改,思路是把loader当store来用
            this.totalCount = o.totalCount;
            this.currentCount = o.data.length;
            var o = o.data;
            node.beginUpdate();
            for(var i = 0, len = o.length; i < len; i++){
                var n = this.createNode(o[i]);
                if(n){
                    node.appendChild(n);
                }
            }
            node.endUpdate();
            this.runCallback(callback, scope || node, [node]);
        }catch(e){
            this.handleFailure(response);
        }
    }
})

?

用法:

var root = new Ext.tree.AsyncTreeNode({   
             text: '数据字典', 
             expanded :false,
             draggable:false,   
             id:"1" });
    var loader = new Ext.tree.TreePagingLoader({   
       dataUrl:"cotmodule.do?method=querySysDic&&query=1" ,
       listeners : {   
          'click' : function(loader,node) { 
          	   //alert(node.href);
               this.baseParams.type = node.id; 
            }
       }
   })  ;
	var store = new Ext.tree.TreeLoaderStore({
		rootNode:root,
		loader:loader
	});
	var bbar = new Ext.PagingToolbar({
		pageSize: 15,
	    store: store,
	    displayInfo: true,
	    displayMsg: '显示第 {0} - {1}条记录 共{2}条记录',
	    displaySize:'5|10|15|20|all',
	    emptyMsg: "无记录"
	});
	var myTree = new Ext.tree.TreePanel({      
        region:"center",
        autoScroll:true,   
        animate:true,   
        enableDD:true,   
        containerScroll: true, 
        bbar:bbar,
        root:root,
        loader:loader
    });   
    store.load({params:{start:0,limit:15}});

?

效果图: