作者:憨哇 | 来源:互联网 | 2023-09-13 18:49
这里讨论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);}
};
这样,当树中某节点被选中时,向上和向下的节点处理就完成了。