Extjs3.4中TreePanel含复选框树选中状态级联处理详解(含半选)

这里讨论TreePanel树含复选框且允许半选状态存在方式,当选中某节点时时,向上和向下的选中情况处理。在允许含半选的情况下,在异步动态获取节点数据时,通常都会在返回节点JSON数组数据中包含indeterminate属性。这里需要注意的是当json数据对象中indeterminate为true时,无论checked为true或false,对应的节点初始化时都会显示为半选状态,并且节点属性checked和indeterminate值都为true。当json数据对象中indeterninate为false时,若checked为true,则初始化节点显示为选中状态,节点属性checked值为true,indeterninate为false;若checked为false时,则初始化节点显示为未选中状态,节点属性checked为false,indeterninate为false。

Html中CheckBox和Ext中CheckBox区别:
1、初始化设置。若Html的CheckBox中indeterminate属性设置为true时,check属性为false;若Extjs的CheckBox中indeterminate属性设置为true,则check属性会为true。
2、动态使用代码改变状态设置。Html中若CheckBox的indeterminate属性值被设置为true,check属性值不会改变;Extjs中CheckBox的Indeterminate属性被设置为true时,需同时更改其UI的Indeterminate属性值为true,并且不会改变其check值,所以需处理使其改变(这里通常会把check属性也设置为true。目的:为了使其在后面代码中用getChecked方法能同时获取到半选和全选复选框)。

Html中CheckBox和Ext中CheckBox相同点:
1、默认不设置indeterminate属性时。Html和Extjs中在初始化不设置的情况下indeterminate属性默认为false。
2、单击改变选中状态:Html中CheckBox在被单击改变复选框状态时,无论之前其indeterminate属性值为true或false,check值会变成相应的true或false,在单击后indeterminate值都会被设置为false。Extjs中CheckBox在被单击时,无论之前indeterminate属性和UI值是true还是false,单击后indeterminate的属性值和UI值都会被设置为false,并且check属性及其UI值都会被改变成对应的属性值。


下面为新建TreePanel实例。
情况一:当选中某节点时,展开并选中所有子孙节点;当取消选中某节点时,级联取消选中所有已加载子孙节点。复选框状态改变时都实现与上级节点关联。

var tree = new Ext.tree.TreePanel({
	id:'itree',
	loader: new Ext.tree.TreeLoader({dataUrl:'findTreeNode.action',baseParams:{}}),
	//是否显示线
	lines:true,
	autoScroll:true,
	root: new Ext.tree.AsyncTreeNode({
		text: '根节点',
		draggable: false,
		id: '0'
	}),
	//不显示根节点
	rootVisible:false,
	listeners:{
		'checkchange':function(node,checked){
			checkAttrSyn(node);//实现UI与属性选中状态同步
			if(checked){//当选中当前节点时,展开并选中所有子孙节点
				expandInherit(node);
			}else{
				checkChilds(node);
			}
			checkParent(this,node);
		}
	}
})

var tree = new Ext.tree.TreePanel({
	id:'itree',
	loader: new Ext.tree.TreeLoader({dataUrl:'findTreeNode.action',baseParams:{}}),
	//是否显示线
	lines:true,
	autoScroll:true,
	root: new Ext.tree.AsyncTreeNode({
		text: '根节点',
		draggable: false,
		id: '0'
	}),
	//不显示根节点
	rootVisible:false,
	listeners:{
		'checkchange':function(node,checked){
			checkAttrSyn(node);//实现UI与属性选中状态同步
			if(checked){//当选中当前节点时,展开并选中所有子孙节点
				expandInheritIncUI(node);
			}else{
				checkChilds(node);
			}
			checkParent(this,node);
		}
	}
})

以上两种实现推荐使用第一种。

情况二
1、若单击选中(或取消选中)本节点,会级联选中(或取消选中)其已加载子孙节点
2、展开本节点时,若本节点为选中(或未选中)状态时,会将本节点选中状态应用于已加载子孙节点;若本节点为半选状态,则不会影响子节点选中状态。
3、复选框状态改变时都实现与上级节点关联。

var tree = new Ext.tree.TreePanel({
	id:'itree',
	loader: new Ext.tree.TreeLoader({dataUrl:'findTreeNode.action',baseParams:{}}),
	//是否显示线
	lines:true,
	autoScroll:true,
	root: new Ext.tree.AsyncTreeNode({
		text: '根节点',
		draggable: false,
		id: '0'
	}),
	//不显示根节点
	rootVisible:false,
	listeners:{
		'checkchange':function(node,checked){
			checkAttrSyn(node);//实现UI与属性选中状态同步
			if(node.loaded) checkChildsIncUI(node);//当本节点子节点已加载,则调用checkChilds方法
			checkParent(this,node);
		},
		//展开节点后触发
		'beforeexpandnode':function(node){
			checkChilds(node);
		}
	}
})

var tree = new Ext.tree.TreePanel({
	id:'itree',
	loader: new Ext.tree.TreeLoader({dataUrl:'findTreeNode.action',baseParams:{}}),
	//是否显示线
	lines:true,
	autoScroll:true,
	root: new Ext.tree.AsyncTreeNode({
		text: '根节点',
		draggable: false,
		id: '0'
	}),
	//不显示根节点
	rootVisible:false,
	listeners:{
		'checkchange':function(node,checked){
			checkAttrSyn(node);//实现UI与属性选中状态同步
			if(node.loaded) checkChildsIncUI(node);//当本节点子节点已加载,则调用checkChilds方法
			checkParent(this,node);
		},
		//展开节点后触发
		'expandnode':function(node){
			checkChildsIncUI(node);
		}
	}
})

以上两种实现推荐使用第一种。

从上面TreePanel实例中可以看出,在选择某个节点复选框或展开某个节点时都有监听处理,其作用是同时向上和向下对节点进行选中状况处理。这里用到了一个属性同步和五个递归的辅助方法,其代码如下:

//实现当前节点UI与TreeNode选择状态属性同步
checkAttrSyn = function(node){
	node.attributes.checked = node.ui.checkbox.checked;
	node.attributes.indeterminate = node.ui.checkbox.indeterminate;
};

//展开当前节点下所有子孙节点,并将当前节点选中状态应用于子孙节点(同时应用属性和UI)
expandInheritIncUI = function(node){
	if(node.isExpanded()){//若该节点已展开,则将当前节点选中状态应用于该节点下所有子孙节点
		checkChilds(node);
		node.eachChild(function(child){
			expandInheritIncUI(child);
		});
	}else{
		var customfun = null;
		node.on("expand",customfun = function(){
			checkChilds(node);
			node.eachChild(function(child){
				expandChildsIncUI(child);
			});
			node.removeListener("expand",customfun,this);
		});
		node.expand();//展开当前节点子节点
	}
};

//展开当前节点下所有子孙节点,并将当前节点选中状态应用于子孙节点(只应用属性)
expandInherit = function(node){
	if(node.isExpanded()){//若该节点已展开,则将当前节点选中状态应用于该节点下所有子孙节点
		checkChilds(node);
		node.eachChild(function(child){
			expandInherit(child);
		});
	}else{
		var customfun = null;
		node.on("beforeexpand",customfun = function(){
			checkChilds(node);
			node.eachChild(function(child){
				expandInherit(child);
			});
			node.removeListener("beforeexpand",customfun,this);
		});
		node.expand();//展开当前节点子节点
	}
};

//将当前节点的选中状态(全选和未选),包括属性和UI应用于向下的所有(已加载)子孙节点
checkChildsIncUI = function(node){
	var checked = node.attributes.checked;
	var half = node.attributes.indeterminate;
	node.eachChild(function(child){
		if(Ext.isBoolean(half) && !half){//判断当前节点是否为半选(半选将不应用于子孙节点)
			child.attributes.checked = checked;
			child.ui.checkbox.checked = checked;
			child.attributes.indeterminate = half;
			child.ui.checkbox.indeterminate = half;
		}
		checkChilds(child);
	});
};

//将当前节点的选中状态(全选和未选),只属性应用于向下的所有(已加载)子孙节点
checkChilds = function(node){
	var checked = node.attributes.checked;
	var half = node.attributes.indeterminate;
	node.eachChild(function(child){
		if(Ext.isBoolean(half) && !half){//判断当前节点是否为半选(半选将不应用于子孙节点)
			child.attributes.checked = checked;
			child.attributes.indeterminate = half;
		}
		checkChilds(child);
	});
};

//选中当前节点时,对向上的父节点选中状态进行处理
checkParent = function(tree,node){
	var parentNode = node.parentNode;
	//由于根节点隐藏且没有复选框,所以当当前节点父节点为根节点时不再对父节点(根节点)进行选中状态处理
	if(tree.root.attributes.id != parentNode.attributes.id){
		//父节点中子节点半选个数计数
		var halfcount = 0;
		//父节点中子节点选中个数计数
		var checkedCount = 0;
		//父节点中子节点数
		var childCount = parentNode.childNodes.length;
		parentNode.eachChild(function(child){
			if(child.attributes.indeterminate){
				halfcount++;
			}else if(child.attributes.checked){
				checkedCount++;
			}
		});
		if(checkedCount == childCount){//若父节点中子节点已被全选,则选中父节点
			parentNode.attributes.checked = true;
			parentNode.ui.checkbox.checked = true;
			parentNode.attributes.indeterminate = false;
			parentNode.ui.checkbox.indeterminate = false;
		}else if(halfcount > 0 || checkedCount > 0){//若父节点的部分子节点为选中或半选时,父节点为半选状态
			parentNode.attributes.checked = true;
			parentNode.ui.checkbox.checked = true;
			parentNode.attributes.indeterminate = true;
			parentNode.ui.checkbox.indeterminate = true;
		}else{//若父节点中子节点未被全选,则将父节点置为不选中
			parentNode.attributes.checked = false;
			parentNode.ui.checkbox.checked = false;
			parentNode.attributes.indeterminate = false;
			parentNode.ui.checkbox.indeterminate = false;
		}
		checkParent(tree,parentNode);
	}
};

 


这样,当树中某节点被选中时,向上和向下的节点处理就完成了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值