网上有很多树的例子,感觉都是不太尽如人意。俗话说,自己动手丰衣足食,自己来做一个吧。
首先三态节点树必须是带有CheckBox的树,这里简单说明一下所做的三态树。所谓三态是指:选中状态,半选中状态,未选中状态。选中状态:节点的CheckBox打勾;半选中状态:节点的CheckBox打勾,但为灰色;未选中状态:CheckBox不打勾。
其次,子节点全选中,父节点选中;子节点全不选中,父节点不选中;子节点选中但未全部选中,父节点半选中;子节点半选中,父节点半选中;父节点选中子节点全选中,父节点取消,子节点全取消。
代码如下:客户端(JAVASCRIPT)
<script type="text/jscript" language="javascript">
function ShowLegend(ControlID,LegendInfo)
{
alert(LegendInfo);
var para = "LegendInfo="+LegendInfo + "&Visible=" + document.all(ControlID).checked;
var myAjax = new Ajax.Request('../ajax/WebFormChangeLegendVisible.aspx',{method: 'get', parameters:para, onComplete: RefreshMap});
}
function RefreshMap(request)
{
var content = request.responseText;
parent.mapview.document.forms[0].submit();
}
function OnTreeNodeChecked()
{
var element = window.event.srcElement;
if (!IsCheckBox(element))
return;
var isChecked = element.checked;
var isIndeterminate = element.Indeterminate;
var tree = TV2_GetTreeById("TreeView1");
var node = TV2_GetNode(tree,element);
TV2_SetChildNodesCheckState(node,isChecked);
//alert(element.id);
var parent = TV2_GetParentNode(tree,node);
TV2_NodeOnChildNodeCheckedChanged(tree,parent,isChecked);
//document.all("txtSelectID").value = "";
var aCheckBox = document.getElementsByTagName("input");
for (var i=0;i<aCheckBox.length;i++)
{
if(aCheckBox[i].type == "checkbox")
{
if(aCheckBox[i].checked)
{
var sID = aCheckBox[i].id;
sID = sID.substring(0,sID.indexOf("CheckBox"));
var obja = document.getElementById(sID.replace('n','t'));
var sSelectID = obja.href.replace("javascript:__doPostBack('TreeView1','s')","")
sSelectID = sSelectID.replace("')","")
var aSelectID = sSelectID.split("\")
}
}
}
}
//设置子节点CheckBox的状态
function TV2_SetChildNodesCheckState(node,isChecked)
{
var childNodes = TV2i_GetChildNodesDiv(node);
if(childNodes == null)
return;
var inputs = WebForm_GetElementsByTagName(childNodes,"INPUT");
if(inputs == null || inputs.length == 0)
return;
for(var i = 0; i < inputs.length; i++)
{
if(IsCheckBox(inputs[i]))
inputs[i].checked = isChecked;
inputs[i].indeterminate = false; //父结点改变状态,子节点灰色消失
}
}
//当子节点CheckBox状态改变引发的父结点状态改变
function TV2_NodeOnChildNodeCheckedChanged(tree,node,isChecked,isIndeterminate)
{
if(node == null)
return;
var childNodes = TV2_GetChildNodes(tree,node);
if(childNodes == null || childNodes.length == 0)
return;
var isAllSame = true;
var Nodegray = isIndeterminate; //节点的灰色
for(var i = 0; i < childNodes.length; i++) //循环子节点
{
var item = childNodes[i]; //获取一个子节点
var value = TV2_NodeGetChecked(item); //获取子节点的checked状态
var value2 = TV2_NodeGetindeterminate(item); //获取子节点的isIndeterminate状态
if(isChecked != value) //如果checkbox的选中状态不相同
{
isAllSame = false;
Nodegray = true;
break;
}
if(value2)
{
Nodegray = true;
}
}
var parent = TV2_GetParentNode(tree,node);
if(isAllSame) //为真:即checkbox的选中状态相同
{
TV2_NodeSetChecked(tree,node,isChecked,Nodegray); //设置当前节点状态
TV2_NodeOnChildNodeCheckedChanged(tree,parent,isChecked,Nodegray); //向父结点递归
}
else //为假,即checkbox的选中状态不相同,或出于灰色状态
{
TV2_NodeSetChecked(tree,node,true,Nodegray); //设置当前节点状态
TV2_NodeOnChildNodeCheckedChanged(tree,parent,true,Nodegray); //向父结点递归
}
}
//get node relative element(etc. checkbox)
function TV2_GetNode(tree,element)
{
var id = element.id.replace(tree.id,"");
id = id.toLowerCase().replace(element.type,"");
id = tree.id + id;
var node = document.getElementById(id);
if(node == null) //leaf node, no "A" node
return element;
return node;
}
//get parent node
function TV2_GetParentNode(tree,node)
{
var div = WebForm_GetParentByTagName(node,"DIV");
var table = div.previousSibling;
if(table == null)
return null;
return TV2i_GetNodeInElement(tree,table);
}
//get child nodes array
function TV2_GetChildNodes(tree,node)
{
if(TV2_NodeIsLeaf(node))
return null;
var children = new Array();
var div = TV2i_GetChildNodesDiv(node);
var index = 0;
for(var i = 0; i < div.childNodes.length; i++)
{
var element = div.childNodes[i];
if(element.tagName != "TABLE")
continue;
var child = TV2i_GetNodeInElement(tree,element);
if(child != null)
children[index++] = child;
}
return children;
}
function TV2_NodeIsLeaf(node)
{
return !(node.tagName == "A"); //Todo
}
//读取结点的Checked状态
function TV2_NodeGetChecked(node)
{
var checkbox = TV2i_NodeGetCheckBox(node);
return checkbox.checked;
}
//读取节点的indeterminate状态
function TV2_NodeGetindeterminate(node)
{
var checkbox = TV2i_NodeGetCheckBox(node);
return checkbox.Indeterminate;
}
//判断:只要该节点有一个子节点被选中,则该节点一定被选中,若有一个子节点为灰色,则该节点为灰色
function TV2_NodeSetChecked(tree,node,isChecked,isIndeterminate)
{
var checkbox = TV2i_NodeGetCheckBox(node);
if(checkbox != null)
{
var childNodes = TV2_GetChildNodes(tree,node); //获取子节点的集合
for(var i = 0; i < childNodes.length; i++)
{
var item = childNodes[i]; //获取一个子节点
var value = TV2_NodeGetChecked(item); //子节点的选中状态
var value2 = TV2_NodeGetindeterminate(item); //子节点的灰色状态
if(value)
{
isChecked = true ;
break;
}
if(value2)//子节点为灰色
{
isInDeterminate=true;
break;
}
}
checkbox.checked = isChecked; //结点选中状态
checkbox.indeterminate = isIndeterminate; //结点是否灰色
}
}
function IsCheckBox(element)
{
if(element == null)
return false;
return (element.tagName == "INPUT" && element.type.toLowerCase() == "checkbox");
}
//get tree
function TV2_GetTreeById(id)
{
return document.getElementById(id);
}
//get div contains child nodes
function TV2i_GetChildNodesDiv(node)
{
if(TV2_NodeIsLeaf(node))
return null;
var childNodsDivId = node.id + "Nodes";
return document.getElementById( childNodsDivId );
}
//find node in element
function TV2i_GetNodeInElement(tree,element)
{
var node = TV2i_GetNodeInElementA(tree,element);
if(node == null)
{
node = TV2i_GetNodeInElementInput(tree,element);
}
return node;
}
//find "A" node
function TV2i_GetNodeInElementA(tree,element)
{
var as = WebForm_GetElementsByTagName(element,"A");
if(as== null || as.length == 0)
return null;
var regexp = new RegExp("^" + tree.id + "n\d+$");
for(var i = 0; i < as.length; i++)
{
if(as[i].id.match(regexp))
{
return as[i];
}
}
return null;
}
//find "INPUT" node
function TV2i_GetNodeInElementInput(tree,element)
{
var as = WebForm_GetElementsByTagName(element,"INPUT");
if(as== null || as.length == 0)
return null;
var regexp = new RegExp("^" + tree.id + "n\d+");
for(var i = 0; i < as.length; i++)
{
if(as[i].id.match(regexp))
{
return as[i];
}
}
return null;
}
//get checkbox of node
function TV2i_NodeGetCheckBox(node)
{
if(IsCheckBox(node))
return node;
var id = node.id + "CheckBox";
return document.getElementById(id);
}
function showtab(m,n,count){
var strPic1='url(../image/1.bmp)';
var strPic2='url(../image/2.bmp)';
if (m==8) {
strPic1='url(../image/switch03_1.gif)';
strPic2='url(../image/switch03_2.gif)'; }
for(var i=1;i<=count;i++){
if (i==n){
getObject(m+'_'+i).style.background=strPic1;
getObject('tab_'+m+'_'+i).style.display='';
}
else {
getObject(m+'_'+i).style.background=strPic2;
getObject('tab_'+m+'_'+i).style.display='none';
}
}
}
function getObject(objectId) {
if(document.getElementById && document.getElementById(objectId)) {
// W3C DOM
return document.getElementById(objectId);
} else if (document.all && document.all(objectId)) {
// MSIE 4 DOM
return document.all(objectId);
} else if (document.layers && document.layers[objectId]) {
// NN 4 DOM.. note: this won't find nested layers
return document.layers[objectId];
} else {
return false;
}
} // getObject
function Init()
{
//var w = document.body.scrollWidth;
var w = document.body.clientWidth;
//var h = document.body.scrollHeight;
var h = document.body.clientHeight;
getObject("tabTree").style.height = h-90;
getObject("divHRTree").style.height=h-100;
}
</script>
function ShowLegend(ControlID,LegendInfo)
{
alert(LegendInfo);
var para = "LegendInfo="+LegendInfo + "&Visible=" + document.all(ControlID).checked;
var myAjax = new Ajax.Request('../ajax/WebFormChangeLegendVisible.aspx',{method: 'get', parameters:para, onComplete: RefreshMap});
}
function RefreshMap(request)
{
var content = request.responseText;
parent.mapview.document.forms[0].submit();
}
function OnTreeNodeChecked()
{
var element = window.event.srcElement;
if (!IsCheckBox(element))
return;
var isChecked = element.checked;
var isIndeterminate = element.Indeterminate;
var tree = TV2_GetTreeById("TreeView1");
var node = TV2_GetNode(tree,element);
TV2_SetChildNodesCheckState(node,isChecked);
//alert(element.id);
var parent = TV2_GetParentNode(tree,node);
TV2_NodeOnChildNodeCheckedChanged(tree,parent,isChecked);
//document.all("txtSelectID").value = "";
var aCheckBox = document.getElementsByTagName("input");
for (var i=0;i<aCheckBox.length;i++)
{
if(aCheckBox[i].type == "checkbox")
{
if(aCheckBox[i].checked)
{
var sID = aCheckBox[i].id;
sID = sID.substring(0,sID.indexOf("CheckBox"));
var obja = document.getElementById(sID.replace('n','t'));
var sSelectID = obja.href.replace("javascript:__doPostBack('TreeView1','s')","")
sSelectID = sSelectID.replace("')","")
var aSelectID = sSelectID.split("\")
}
}
}
}
//设置子节点CheckBox的状态
function TV2_SetChildNodesCheckState(node,isChecked)
{
var childNodes = TV2i_GetChildNodesDiv(node);
if(childNodes == null)
return;
var inputs = WebForm_GetElementsByTagName(childNodes,"INPUT");
if(inputs == null || inputs.length == 0)
return;
for(var i = 0; i < inputs.length; i++)
{
if(IsCheckBox(inputs[i]))
inputs[i].checked = isChecked;
inputs[i].indeterminate = false; //父结点改变状态,子节点灰色消失
}
}
//当子节点CheckBox状态改变引发的父结点状态改变
function TV2_NodeOnChildNodeCheckedChanged(tree,node,isChecked,isIndeterminate)
{
if(node == null)
return;
var childNodes = TV2_GetChildNodes(tree,node);
if(childNodes == null || childNodes.length == 0)
return;
var isAllSame = true;
var Nodegray = isIndeterminate; //节点的灰色
for(var i = 0; i < childNodes.length; i++) //循环子节点
{
var item = childNodes[i]; //获取一个子节点
var value = TV2_NodeGetChecked(item); //获取子节点的checked状态
var value2 = TV2_NodeGetindeterminate(item); //获取子节点的isIndeterminate状态
if(isChecked != value) //如果checkbox的选中状态不相同
{
isAllSame = false;
Nodegray = true;
break;
}
if(value2)
{
Nodegray = true;
}
}
var parent = TV2_GetParentNode(tree,node);
if(isAllSame) //为真:即checkbox的选中状态相同
{
TV2_NodeSetChecked(tree,node,isChecked,Nodegray); //设置当前节点状态
TV2_NodeOnChildNodeCheckedChanged(tree,parent,isChecked,Nodegray); //向父结点递归
}
else //为假,即checkbox的选中状态不相同,或出于灰色状态
{
TV2_NodeSetChecked(tree,node,true,Nodegray); //设置当前节点状态
TV2_NodeOnChildNodeCheckedChanged(tree,parent,true,Nodegray); //向父结点递归
}
}
//get node relative element(etc. checkbox)
function TV2_GetNode(tree,element)
{
var id = element.id.replace(tree.id,"");
id = id.toLowerCase().replace(element.type,"");
id = tree.id + id;
var node = document.getElementById(id);
if(node == null) //leaf node, no "A" node
return element;
return node;
}
//get parent node
function TV2_GetParentNode(tree,node)
{
var div = WebForm_GetParentByTagName(node,"DIV");
var table = div.previousSibling;
if(table == null)
return null;
return TV2i_GetNodeInElement(tree,table);
}
//get child nodes array
function TV2_GetChildNodes(tree,node)
{
if(TV2_NodeIsLeaf(node))
return null;
var children = new Array();
var div = TV2i_GetChildNodesDiv(node);
var index = 0;
for(var i = 0; i < div.childNodes.length; i++)
{
var element = div.childNodes[i];
if(element.tagName != "TABLE")
continue;
var child = TV2i_GetNodeInElement(tree,element);
if(child != null)
children[index++] = child;
}
return children;
}
function TV2_NodeIsLeaf(node)
{
return !(node.tagName == "A"); //Todo
}
//读取结点的Checked状态
function TV2_NodeGetChecked(node)
{
var checkbox = TV2i_NodeGetCheckBox(node);
return checkbox.checked;
}
//读取节点的indeterminate状态
function TV2_NodeGetindeterminate(node)
{
var checkbox = TV2i_NodeGetCheckBox(node);
return checkbox.Indeterminate;
}
//判断:只要该节点有一个子节点被选中,则该节点一定被选中,若有一个子节点为灰色,则该节点为灰色
function TV2_NodeSetChecked(tree,node,isChecked,isIndeterminate)
{
var checkbox = TV2i_NodeGetCheckBox(node);
if(checkbox != null)
{
var childNodes = TV2_GetChildNodes(tree,node); //获取子节点的集合
for(var i = 0; i < childNodes.length; i++)
{
var item = childNodes[i]; //获取一个子节点
var value = TV2_NodeGetChecked(item); //子节点的选中状态
var value2 = TV2_NodeGetindeterminate(item); //子节点的灰色状态
if(value)
{
isChecked = true ;
break;
}
if(value2)//子节点为灰色
{
isInDeterminate=true;
break;
}
}
checkbox.checked = isChecked; //结点选中状态
checkbox.indeterminate = isIndeterminate; //结点是否灰色
}
}
function IsCheckBox(element)
{
if(element == null)
return false;
return (element.tagName == "INPUT" && element.type.toLowerCase() == "checkbox");
}
//get tree
function TV2_GetTreeById(id)
{
return document.getElementById(id);
}
//get div contains child nodes
function TV2i_GetChildNodesDiv(node)
{
if(TV2_NodeIsLeaf(node))
return null;
var childNodsDivId = node.id + "Nodes";
return document.getElementById( childNodsDivId );
}
//find node in element
function TV2i_GetNodeInElement(tree,element)
{
var node = TV2i_GetNodeInElementA(tree,element);
if(node == null)
{
node = TV2i_GetNodeInElementInput(tree,element);
}
return node;
}
//find "A" node
function TV2i_GetNodeInElementA(tree,element)
{
var as = WebForm_GetElementsByTagName(element,"A");
if(as== null || as.length == 0)
return null;
var regexp = new RegExp("^" + tree.id + "n\d+$");
for(var i = 0; i < as.length; i++)
{
if(as[i].id.match(regexp))
{
return as[i];
}
}
return null;
}
//find "INPUT" node
function TV2i_GetNodeInElementInput(tree,element)
{
var as = WebForm_GetElementsByTagName(element,"INPUT");
if(as== null || as.length == 0)
return null;
var regexp = new RegExp("^" + tree.id + "n\d+");
for(var i = 0; i < as.length; i++)
{
if(as[i].id.match(regexp))
{
return as[i];
}
}
return null;
}
//get checkbox of node
function TV2i_NodeGetCheckBox(node)
{
if(IsCheckBox(node))
return node;
var id = node.id + "CheckBox";
return document.getElementById(id);
}
function showtab(m,n,count){
var strPic1='url(../image/1.bmp)';
var strPic2='url(../image/2.bmp)';
if (m==8) {
strPic1='url(../image/switch03_1.gif)';
strPic2='url(../image/switch03_2.gif)'; }
for(var i=1;i<=count;i++){
if (i==n){
getObject(m+'_'+i).style.background=strPic1;
getObject('tab_'+m+'_'+i).style.display='';
}
else {
getObject(m+'_'+i).style.background=strPic2;
getObject('tab_'+m+'_'+i).style.display='none';
}
}
}
function getObject(objectId) {
if(document.getElementById && document.getElementById(objectId)) {
// W3C DOM
return document.getElementById(objectId);
} else if (document.all && document.all(objectId)) {
// MSIE 4 DOM
return document.all(objectId);
} else if (document.layers && document.layers[objectId]) {
// NN 4 DOM.. note: this won't find nested layers
return document.layers[objectId];
} else {
return false;
}
} // getObject
function Init()
{
//var w = document.body.scrollWidth;
var w = document.body.clientWidth;
//var h = document.body.scrollHeight;
var h = document.body.clientHeight;
getObject("tabTree").style.height = h-90;
getObject("divHRTree").style.height=h-100;
}
</script>
当然,仅有客户端的代码是不够的。我们还需要在服务器端构造一棵树。最简单的方法就是从工具箱——〉导航 中将一个TreeView控件拖到页面上。在TreeView的属性——〉行为中的“ShowCheckBox”一项改为“all”,这样,一个带有CheckBox的树就构造成功了。在服务器端的Page_Load下加入代码:
if (!Page.IsPostBack)
{
//转入前台的 OnTreeNodeChecked()
TreeView1.Attributes.Add("onclick", "OnTreeNodeChecked()");
}
{
//转入前台的 OnTreeNodeChecked()
TreeView1.Attributes.Add("onclick", "OnTreeNodeChecked()");
}
当然,树中的节点是用户自己添加还是从数据库中读取出来的还是从域中读取出来的这都不是我们讨论的问题,现在,我们的三态树已经大功告成了。你可以手动为树添加几个节点测试一个,代码不需要做修改,按以上步骤COPE到自己页面上就可以用,唯一要改的就是你创建的TreeView的名字,我的代码中的TreeView的名字为TreeView1。有什么问题可以给我留言大家一起讨论。^ ^