树形结构改良版

这篇文章是对前一篇文章树形结构的改良,并实现了更多的功能,其中包含禁止选择不同的城市,不同的学校(注:这些是我们项目中的需要,有一定的特殊性,主要是为了防止同时选中过多的对象然后发送信息的时候会发生堵塞。)

与上一个版本相比,现在的版本增加了两个方法cancelSchool(self),cancelCity(self),并且取消了label标签,所以点击A标签的时候只会有展开或收缩的功能,这样做的目的是为了避免在ajax第一次加载子对象数据时会只选择当前的checkbox,而由于加载完后的子对象却没法选中。然后把原来的span标签换成了em标签,这样em和a标签所触发的事件是一样的了。该版本稍微修改后已经在实际项目中应用到了,使用的ajax加载子对象,避免一次性加载的时候数据量过大,导致等候页面时间过长。

下面是完整的代码,代码里有部分注释,其中的展开收缩图片在前一篇文章中给出,这里就不重复了。

代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<meta name="copyright" content="" />
<meta name="keywords" content="" />
<meta name="description" content="" />
<title></title>
<style>
body
{padding:0; margin:0; font: 12px/1.5 Tahoma, Helvetica, Arial, sans-serif;}
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote,dl, dt, dd, ul, ol, li,pre,form, fieldset, legend, button, input, textarea,th, td
{margin: 0;padding: 0;}
button, input, select, textarea
{font: 12px/1.5 tahoma, arial, simsun, sans-serif;}
h1, h2, h3, h4, h5, h6
{ font-size: 100%;font-weight:normal; }
address, cite, dfn, em, var
{ font-style: normal; }
code, kbd, pre, samp
{ font-family: courier new, courier, monospace; }
small
{ font-size: 12px; }
ul, ol
{ list-style: none; }
sup
{ vertical-align: text-top; }
sub
{ vertical-align: text-bottom; }
legend
{ color: #000; }
fieldset, img
{ border: 0; }
button, input, select, textarea
{ font-size: 100%; }
table
{ border-collapse: collapse; border-spacing: 0; }
.clear
{clear:both;}
html
{ overflow:-moz-scrollbars-vertical; }
a
{ text-decoration: none;}
a:hover
{ text-decoration: underline;}

#root
{margin:10px;width:200px;overflow:hidden;}
#root li
{line-height:25px;}
#root span
{display:inline-block;}
#root .rem
{padding-left:16px;}
#root .add
{background:url(add.gif) -4px -31px no-repeat;}
#root .ren
{background:url(add.gif) -4px -7px no-repeat;}
#root li a
{color:#666666;padding-left:5px;outline:none;blr:expression(this.onFocus=this.blur()); }
#root li input
{vertical-align:middle;margin-left:5px;}
#root .two
{padding-left:20px;display:none;}
#root em
{display: inline-block; height: 16px; vertical-align: middle; width: 16px; cursor: pointer;_margin-bottom:-10px;}

</style>
</head>

<body>
<h1>树形结构</h1>
<ul id="root">
<li>
<em class="add">&nbsp;</em><span><a href="javascript:;">校讯通</a></span>
<ul class="two">
<li>
<em class="add" onclick="toggle(this);">&nbsp;</em><span><a href="javascript:;" onclick="toggle(this);">沈阳市</a></span>
<ul class="two">
<li>
<span><input type="checkbox" value="123456" /><a href="javascript:;">二小</a></span>
<ul class="two">
<li><span><input type="checkbox" value="123456"/><a href="javascript:;">二年级</a></span></li>
<li>
<span><input type="checkbox" value="123456"/><a href="javascript:;">三年级</a></span>
<ul class="two">
<li>
<span><input type="checkbox" value="123456"/><a href="javascript:;">一班</a></span>
<ul class="two">
<li><span><input type="checkbox" value="123456"/><a href="javascript:;">张三</a></span></li>
<li><span><input type="checkbox" value="123456"/><a href="javascript:;">王五</a></span></li>
</ul>
</li>
<li><span><input type="checkbox" value="123456"/><a href="javascript:;">实验班</a></span></li>
</ul>
</li>
</ul>
</li>
<li>
<span><input type="checkbox" value="33333" /><a href="javascript:;">三小</a></span>
<ul class="two">
<li><span><input type="checkbox" value="123456"/><a href="javascript:;">一年级</a></span></li>
<li>
<span><input type="checkbox" value="66666"/><a href="javascript:;">六年级</a></span>
<ul class="two">
<li>
<span><input type="checkbox" value="123456"/><a href="javascript:;">二班</a></span>
</li>
<li><span><input type="checkbox" value="123456"/><a href="javascript:;">实验班</a></span></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<em class="add" onclick="toggle(this);">&nbsp;</em><span><a href="javascript:;" onclick="toggle(this);">抚顺市</a></span>
<ul class="two">
<li><span><input type="checkbox" value="123456"/><a href="javascript:;">二小</a></span></li>
<li><span><input type="checkbox" value="123456"/><a href="javascript:;">一中</a></span></li>
</ul>
</li>
</ul>
</li>
</ul>
</body>
<script type="text/javascript" >
function toggle(self){//城市的点击事件
var children;
if(self.nodeName == 'A')
children
= self.parentNode.parentNode.parentNode.childNodes;
else
children
= self.parentNode.parentNode.childNodes;
for(var i=0;i<children.length;i++){
if(children[i].nodeType == 1&&children[i]!=self.parentNode.parentNode){
children[i].getElementsByTagName(
'ul')[0].style.display ='none';
for(var k=0;k<children[i].childNodes.length;k++){
if(children[i].childNodes[k].nodeName == 'EM')
children[i].childNodes[k].className
= 'add';
}
}
}
}
function addEvent(el,name,fn){ //绑定事件
if(el.addEventListener) return el.addEventListener(name,fn,false);
return el.attachEvent('on'+name,fn);
}
function nextnode(node){ //寻找下一个兄弟并剔除空的文本节点
if(!node)return ;
if(node.nodeType == 1)
return node;
if(node.nextSibling)
return nextnode(node.nextSibling);
}
function prevnode(node){ //寻找上一个兄弟并剔除空的文本节点
if(!node)return ;
if(node.nodeType == 1)
return node;
if(node.previousSibling)
return prevnode(node.previousSibling);
}
function parcheck(self,checked){ //递归寻找父亲元素,并找到input元素进行操作
var par = prevnode(self.parentNode.parentNode.parentNode.previousSibling),parspar;
if(par&&par.getElementsByTagName('input')[0]){
par.getElementsByTagName(
'input')[0].checked = checked;
parcheck(par.getElementsByTagName(
'input')[0],sibcheck(par.getElementsByTagName('input')[0]));
}
}
function sibcheck(self){ //判断兄弟节点是否已经全部选中
var sbi = self.parentNode.parentNode.parentNode.childNodes,n=0;
for(var i=0;i<sbi.length;i++){
if(sbi[i].nodeType != 1) //由于孩子结点中包括空的文本节点,所以这里累计长度的时候也要算上去
n++;
else if(sbi[i].getElementsByTagName('input')[0].checked)
n
++;
}
return n==sbi.length?true:false;
}
function partop(self){//寻找顶层的checkbox并返回
var par = prevnode(self.parentNode.parentNode.parentNode.previousSibling),parspar;
if(par&&par.getElementsByTagName('input')[0])
return partop(par.getElementsByTagName('input')[0]);
else
return self;
}
function cancelSchool(self){//禁止同时选中多个学校
var par = partop(self).parentNode.parentNode;
var children = par.parentNode.childNodes;
for(var i=0;i<children.length;i++){
if(children[i] != par&&children[i].nodeType == 1&&children[i].getElementsByTagName('input')){
var inputs = children[i].getElementsByTagName('input');
for(var j=0;j<inputs.length;j++)
inputs[j].checked
= false;
}
}
}
function cancelCity(self){//禁止选中多个城市
var toppar = partop(self).parentNode.parentNode.parentNode.parentNode;
var children = toppar.parentNode.childNodes;
if(toppar){
for(var i=0;i<children.length;i++){
if(children[i].nodeType == 1&&children[i]!=toppar){
var inputs = children[i].getElementsByTagName('input');
for(var j=0;j<inputs.length;j++)
inputs[j].checked
= false;
}
}
}
}
addEvent(document.getElementById(
'root'),'click',function(e){//绑定input点击事件,使用root根元素代理
e = e||window.event;
var target = e.target||e.srcElement;
var tp = nextnode(target.parentNode.nextSibling);
switch(target.nodeName){
case 'A': //点击A标签展开和收缩树形目录,并改变其样式会选中checkbox
if(tp&&tp.nodeName == 'UL'){
if(tp.style.display != 'block' ){
tp.style.display
= 'block';
prevnode(target.parentNode.previousSibling).className
= 'ren'
}
else{
tp.style.display
= 'none';
prevnode(target.parentNode.previousSibling).className
= 'add'
}
}
break;
case 'EM': //点击图标只展开或者收缩
var ap = nextnode(nextnode(target.nextSibling).nextSibling);
if(ap.style.display != 'block' ){
ap.style.display
= 'block';
target.className
= 'ren'
}
else{
ap.style.display
= 'none';
target.className
= 'add'
}
break;
case 'INPUT'://点击checkbox,父亲元素选中,则孩子节点中的checkbox也同时选中,孩子结点取消父元素随之取消
if(target.checked){
cancelCity(target);
cancelSchool(target);
if(tp){
var checkbox = tp.getElementsByTagName('input');
for(var i=0;i<checkbox.length;i++)
checkbox[i].checked
= true;
}
}
else{
if(tp){
var checkbox = tp.getElementsByTagName('input');
for(var i=0;i<checkbox.length;i++)
checkbox[i].checked
= false;
}
}
parcheck(target,sibcheck(target));
//当孩子结点取消选中的时候调用该方法递归其父节点的checkbox逐一取消选中
break;
}
});
window.onload
= function(){//页面加载时给有孩子结点的元素动态添加图标
var spans = document.getElementById('root').getElementsByTagName('span');
for(var i=0;i<spans.length;i++){
var em = document.createElement('em');
em.innerHTML
= '&nbsp;'
em.className
= 'add';
if(nextnode(spans[i].nextSibling)&&nextnode(spans[i].nextSibling).nodeName == 'UL'&&spans[i].getElementsByTagName('input')[0])
spans[i].parentNode.insertBefore(em,spans[i]);
else if(!nextnode(spans[i].nextSibling)||nextnode(spans[i].nextSibling).nodeName != 'UL')
spans[i].className
= 'rem'
}
}
</script>
</html>

 

如代码存在bug,欢迎指正,不胜感激!

posted @ 2010-10-14 17:09  冰封e族  阅读(375)  评论(0编辑  收藏  举报