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

ExtJS中树形结构级联选中(三态)
在使用ExtJS进行开发时,常常遇到需要用到树形结构Ext.tree.TreePanel,而且经常需要对TreePanel进行级联选中与取消选中,我们的做法无非就是监听checkchange事件进行相应的处理,常用的写法是:
var treePanel = new Ext.tree.TreePanel({
...
listeners : {
'checkchange' : function(){
...
}
}
});

这样做可行吗,答案是肯定的,肯定是可以实现的,只是当你需要多个地方都需要进行级联选中时,你需要拷贝这些代码到需要的地方,这样写代码有些糟糕,复用性太低,也不易于维护,同时,这样写不是很好实现checkbox的三种状态,于是动手写了这样一个插件,实现了树形结构的级联选中与三态,代码如下:
/* 带有CheckBox的树的选中的插件
 * author:jn_nian
 * createTime:2010-10-24 21:46
 * usage: Ext3使用 plugins : ['treecheck']或plugins:[new Ext.ux.TreePanelCheck()]
 * Ext2使用 :plugins:[new Ext.ux.TreePanelCheck()]
*******************************************************************/
 
 Ext.ux.TreePanelCheck = Ext.extend(Ext.tree.TreePanel,{
 	init : function(treePanel){
 		var rootNode = treePanel.getRootNode();
 		
 		treePanel.on('expandnode',this.doLazyCheck,rootNode);
 		treePanel.on('checkchange',this.handlerCheck,this);
 	},
 	
 	
 	//检查子结点选中的情况
 	doChildHasChecked : function(node){
 		var childNodes = node.childNodes;
		var checkedNum = 0;
		if(childNodes || childNodes.length>0){
			for(var i=0;i<childNodes.length;i++){
				if(childNodes[i].getUI().checkbox.checked){
    				checkedNum = checkedNum + 1;
				}
			}
		}
		return checkedNum;
 	},
 	
 	//父节点选中
 	doParentCheck : function(node ,checked){
 		var checkbox = node.getUI().checkbox;
		if(typeof checkbox == 'undefined') return false;
		node.getUI().checkbox.indeterminate = false;
		node.getUI().checkbox.checked = checked;
		
		node.attributes.checked = checked;
		var childChecked = this.doChildHasChecked(node);
		if(childChecked == node.childNodes.length){
			node.getUI().checkbox.checked = true;
			node.getUI().checkbox.indeterminate = false;
		}else if(childChecked == 0){
			var indeterminate = false;
			node.eachChild(function(child){     
	        	if(child.getUI().checkbox.indeterminate){
	        		indeterminate = true;
	        		return false;
	        	}
	        }); 
			node.getUI().checkbox.checked = false;
			node.getUI().checkbox.indeterminate = indeterminate;
		}else{
			node.getUI().checkbox.checked = false;
			node.getUI().checkbox.indeterminate = true; //半选中状态
		}
		
		node.getOwnerTree().fireEvent('check', node, checked);
		var parentNode = node.parentNode;
		if( parentNode !== null){
			this.doParentCheck(parentNode,checked);
		}
 	},
 	
 	handlerCheck : function(node,checked){
 		var parentNode = node.parentNode;
        if(!Ext.isEmpty(parentNode)) {   
        	this.doParentCheck(parentNode,checked);   
        }
        node.attributes.checked = checked;
//		node.expandChildNodes(true);
        node.eachChild(function(child){     
        	child.ui.toggleCheck(checked);    
            child.attributes.checked = checked;     
            child.fireEvent('checkchange', child, checked);
        });
 	},
 	
 	//延迟加载选中
 	doLazyCheck : function(node){
 		if(!Ext.isEmpty(node.parentNode)){
			var nodeChecked = node.getUI().checkbox.checked;
			//node.expandChildNodes(true);
			node.eachChild(function(child){
				child.getUI().checkbox.checked = nodeChecked;
			});
		}
 	},
 	
 	getPType : function(){
 		return this.ptype;
 	}
 });
 Ext.preg('treecheck',Ext.ux.TreePanelCheck);

此代码可以在Ext2.x与3.x下正常运行,当你使用Ext3.x时你不需要对此代码作任何改动,当你使用Ext2.x时,请注释掉最后一行代码:Ext.preg('treecheck',Ext.ux.TreePanelCheck);
最终实现效果图如附件中所示
1 楼 tkl211 2012-05-30  
我用这个插件出现这个问题。
比如我 三级菜单
10001
    10002
         10003
         10004
(1)我选中 10001的时候,这时候级联选中子节点是没问题,我后台获取id也是这四个,但是当我取消 10003的时候, 这时候取得的checked值 只有 10004 这一个,而10001,10002这时候应该处于半选中状态,应该也能取得值才对的,但是去无法取到值。
(2)我初始化的时候, 10001,10002,10003的checked 是true,10004的为false,这时候,会把我10004这个也默认选中的。
2