原来那位老兄是用一般方法写成的无限级折叠菜

作者: 前端  发布:2019-09-06

onmouseout 发现它的触发太敏感,当经过层内文字链时,即触发onmousetout事件,功能不能正常显示,经过一番搜索,整理出来,供大家参考。

本例是应用别人的例子,原来那位老兄是用一般方法写成的无限级折叠菜单,在此先感谢他!后来我就通过了一些简化修改,将原来的例子改成了面向对象的方式,实例中的展开与闭合的小图标可以自己重新添加,从而更好的查看效果。

数据源用数组混json结构,实现了基本的功能。效率一般,跟 dhtree 梅花雪树对比了下,都差不多。 (ps感觉比dhtree快点,跟梅花雪树差不多,个人测试)

1、

复制代码 代码如下:

这个实现树的原理是根据json,不断的生成ul li, 下面是一个简单的例子(只有涉及到生成树,也就是说只是展示,tree类代码只有64行) 没有用innerHTML生成,全是是创建节点来创建ul li,所以创建节点碎片添加,然后再一次性添加很重要啊,确实能提高速度。

复制代码 代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ";
<html xmlns=";
<head>
<title>很实用的JS CSS多级树形展开菜单</title>
<style type="text/css">
body{margin:0;padding:0;font:12px/1.5 Tahoma,Helvetica,Arial,sans-serif;}
ul,li,{margin:0;padding:0;}
ul{list-style:none;}
a{text-decoration: none;}
#root{margin:10px;width:200px;overflow:hidden;}
#root li{line-height:25px;}
#root .rem{padding-left:16px;}
#root .add{background:url(treeico.gif) -4px -31px no-repeat;}
#root .ren{background:url(treeico.gif) -4px -7px no-repeat;}
#root li a{color:#666666;padding-left:5px;outline:none;blr:expression(this.onFocus=this.blur());}
#root .two{padding-left:20px;display:none;}
</style>
</head>
<body>
<ul id="root">
<li>
<label><a href="javascript:;">校讯通</a></label>
<ul class="two">
<li>
<label><a href="javascript:;">沈阳市</a></label>
<ul class="two">
<li>
<label><a href="javascript:;">二小</a></label>
<ul class="two">
<li><label><a href="javascript:;">二年级</a></label></li>
<li>
<label><a href="javascript:;">三年级</a></label>
<ul class="two">
<li>
<label><a href="javascript:;">一班</a></label>
<ul class="two">
<li><label><a href="javascript:;">张三</a></label></li>
<li>
<label><a href="javascript:;">王五</a></label>
<ul class="two">
<li><label><a href="javascript:;">班长</a></label></li>
<li><label><a href="javascript:;">学习委员</a></label></li>
</ul>
</li>
</ul>
</li>
<li><label><a href="javascript:;">实验班</a></label></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<label><a href="javascript:;">抚顺市</a></label>
<ul class="two">
<li><label><a href="javascript:;">二小</a></label></li>
<li><label><a href="javascript:;">一中</a></label></li>
</ul>
</li>
</ul>
</li>
</ul>
<script type="text/javascript" >
/**一般JS方法
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);
}
addEvent(document.getElementById('root'),'click',function(e){//绑定点击事件,使用root根元素代理
e = e||window.event;
var target = e.target||e.srcElement;
var tp = nextnode(target.parentNode.nextSibling);
switch(target.nodeName){
case 'A'://点击A标签展开和收缩树形目录,并改变其样式
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 'SPAN'://点击图标只展开或者收缩
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;
}
});
window.onload = function(){//页面加载时给有孩子结点的元素动态添加图标
var labels = document.getElementById('root').getElementsByTagName('label');
for(var i=0;i<labels.length;i ){
var span = document.createElement('span');
span.style.cssText ='display:inline-block;height:18px;vertical-align:middle;width:16px;cursor:pointer;';
span.innerHTML = ' '
span.className = 'add';
if(nextnode(labels[i].nextSibling)&&nextnode(labels[i].nextSibling).nodeName == 'UL')
labels[i].parentNode.insertBefore(span,labels[i]);
else
labels[i].className = 'rem'
}
}
**/
//面向对象方法
var Tree = function(o){
this.root = document.getElementById(o);
this.labels = this.root.getElementsByTagName('label');
9159.com,var that = this;
this.int();
Tree.prototype.addEvent(this.root,'click',function(e){that.treeshow(e)});
}
Tree.prototype = {
int:function(){//初始化页面,加载时给有孩子结点的元素动态添加图标
for(var i=0;i<this.labels.length;i ){
var span = document.createElement('span');
span.style.cssText ='display:inline-block;height:18px;vertical-align:middle;width:16px;cursor:pointer;';
span.innerHTML = ' '
span.className = 'add';
if(this.nextnode(this.labels[i].nextSibling)&&this.nextnode(this.labels[i].nextSibling).nodeName == 'UL')
this.labels[i].parentNode.insertBefore(span,this.labels[i]);
else
this.labels[i].className = 'rem'
}
},
treeshow:function(e){
e = e||window.event;
var target = e.target||e.srcElement;
var tp = this.nextnode(target.parentNode.nextSibling);
switch(target.nodeName){
case 'A'://点击A标签展开和收缩树形目录,并改变其样式
if(tp&&tp.nodeName == 'UL'){
if(tp.style.display != 'block' ){
tp.style.display = 'block';
this.prevnode(target.parentNode.previousSibling).className = 'ren'
}else{
tp.style.display = 'none';
this.prevnode(target.parentNode.previousSibling).className = 'add'
}
}
break;
case 'SPAN'://点击图标只展开或者收缩
var ap = this.nextnode(this.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;
}
},
addEvent:function(el,name,fn){//绑定事件
if(el.addEventListener) return el.addEventListener(name,fn,false);
return el.attachEvent('on' name,fn);
},
nextnode:function(node){//寻找下一个兄弟并剔除空的文本节点
if(!node)return ;
if(node.nodeType == 1)
return node;
if(node.nextSibling)
return this.nextnode(node.nextSibling);
},
prevnode:function(node){//寻找上一个兄弟并剔除空的文本节点
if(!node)return ;
if(node.nodeType == 1)
return node;
if(node.previousSibling)
return prevnode(node.previousSibling);
}
}
tree = new Tree("root");//实例化应用
</script>
</body>
</html>

<!DOCTYPE html> <html xmlns="; <head> <meta http-equiv="Content-Type" content="text/html; charset=gb-2312" /> <title>easytree</title> <style type="text/css"> ul,li{ list-style: none outside none; margin: 0; overflow: hidden; padding: 0; } #demo{ background-color:#F0FBEB; } #demo .root{ margin-left: -20px; } #demo ul{ padding-left: 20px; } #demo .folder{ background: url("../../images/201202/r_i.png") repeat-y scroll 0 21px transparent; } #demo img{ background: url("../../images/201202/r_icon.png") no-repeat scroll 0 0 transparent; border: medium none; height: 20px; vertical-align: top; width: 20px; } #demo .tvicon-open{ background-position: -160px -40px; } #demo .tvdash-f{ background-position: -240px -40px; } #demo .tvdash-f-open{ background-position: -200px -40px; } #demo .tvdash-fl{ background-position: -100px -40px; } #demo .tvdash-fl-open{ background-position: -80px -40px; } #demo .tvdash-t{ background-position: -180px -40px; } #demo .tvdash-tl{ background-position: -60px -40px; } </style> </head> <body> <div id='sss'></div> <div id='demo'></div> <script> (function(doc,undefined){ var window = this; window.Sys = function (ua){ var b = { ie: /msie/.test(ua) && !/opera/.test(ua), opera: /opera/.test(ua), safari: /webkit/.test(ua) && !/chrome/.test(ua), firefox: /firefox/.test(ua), chrome: /chrome/.test(ua) },vMark = ""; for (var i in b) { if (b[i]) { vMark = "safari" == i ? "version" : i; break; } } b.version = vMark && RegExp("(?:" vMark ")[\/: ]([\d.] )").test(ua) ? RegExp.$1 : "0"; b.ie6 = b.ie && parseInt(b.version, 10) == 6; b.ie7 = b.ie && parseInt(b.version, 10) == 7; b.ie8 = b.ie && parseInt(b.version, 10) == 8; return b; }(window.navigator.userAgent.toLowerCase()); window.Sys.ie6&&doc.execCommand("BackgroundImageCache", false, true); window.$$ = function(Id){ return doc.getElementById(Id); }; window.$c = function(name,parent){ var elem = doc.createElement(name); parent&&parent.appendChild(elem); return elem; }; window.addListener = function(element,e,fn){ !element.events&&(element.events = {}); element.events[e]&&(element.events[e][addListener.guid ]=fn)||(element.events[e] = {'0':fn}); element.addEventListener?element.addEventListener(e,fn,false):element.attachEvent("on"

<script type="text/javascript">
  function test(obj, e) {
    if (e.currentTarget) {
  if (e.relatedTarget != obj) {
   if (obj != e.relatedTarget.parentNode) {
  alert(1);
  }
  }
  } else {
  if (e.toElement != obj) {
  if (obj != e.toElement.parentNode) {
  alert(1);
  }
  }
  }
  }
</script>
  <div onmouseout="test(this, event)" style="width:100px;height:100px;border:1px #666 solid">
    <span style="margin:5px;width:100%;height:100%;border:1px #ff0000 solid">faddsf</span>  </div>

您可能感兴趣的文章:

  • javascript仿qq界面的折叠菜单实现代码
  • js实现超简单的展开、折叠目录代码
  • JS实现鼠标滑过折叠与展开菜单效果代码
  • JavaScript可折叠区域实现代码
  • JS实现无限级网页折叠菜单(类似树形菜单)效果代码
  • JS实现的竖向折叠菜单代码
  • js实现带缓冲效果的仿QQ面板折叠菜单代码
  • JS实现仿QQ面板的手风琴效果折叠菜单代码
  • JS CSS实现的竖向简洁折叠菜单效果代码
  • Javascript实现代码折叠功能
  • e,fn); }; window.addListener.guid = 1; window.removeListener = function(element,e,fn){ var handlers = element.events[e],type; if(fn){ for(type in handlers) if(handlers[type]===fn){ element.removeEventListener?element.removeEventListener(e,fn,false):element.detachEvent("on"
  • e,fn); delete handlers[type]; } }else{ for(type in handlers){ element.removeEventListener?element.removeEventListener(e,handlers[type],false):element.detachEvent("on"
  • e,handlers[type]); delete handlers[type]; } } }; window.setStyle = function(e,o){ if(typeof o=="string") e.style.cssText=o; else for(var i in o) e.style[i] = o[i]; }; var slice = Array.prototype.slice; window.Bind = function(object, fun) { var args = slice.call(arguments).slice(2); return function() { return fun.apply(object, args); }; }; window.BindAsEventListener = function(object, fun,args) { var args = slice.call(arguments).slice(2); return function(event) { return fun.apply(object, [event || window.event].concat(args)); } }; //copy from jQ window.extend = function(){ var target = arguments[0] || {}, i = 1, length = arguments.length, deep = true, options; if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; i = 2; } if ( typeof target !== "object" && Object.prototype.toString.call(target)!="[object Function]") target = {}; for(;i<length;i ){ if ( (options = arguments[ i ]) != null ) for(var name in options){ var src = target[ name ], copy = options[ name ]; if ( target === copy ) continue; if ( deep && copy && typeof copy === "object" && !copy.nodeType ){ target[ name ] = arguments.callee( deep, src || ( copy.length != null ? [ ] : { } ), copy ); } else if(copy !== undefined) target[ name ] = copy; } } return target; }; //copy from jQ window.each = function ( object, callback, args ) { var name, i = 0, length = object.length; if ( args ) { args = Array.prototype.slice.call(arguments).slice(2); if ( length === undefined ) { for ( name in object ) if ( callback.apply( object[ name ],[name,object[ name ]].concat(args) ) === false ) break; } else for ( ; i < length; i ) if ( callback.apply( object[ i ],[i,object[ i ]].concat(args)) === false ) // break; } else { if ( length === undefined ) { for ( name in object ) if ( callback.call( object[ name ], name, object[ name ] ) === false ) break; } else for ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[ i] ){} } return object; }; window.currentStyle = function(element){ return element.currentStyle || doc.defaultView.getComputedStyle(element, null); }; window.objPos = function(elem){ var left = 0, top = 0, right = 0, bottom = 0,doc = elem ? elem.ownerDocument : doc; if ( !elem.getBoundingClientRect || window.Sys.ie8 ) { var n = elem; while (n) { left = n.offsetLeft, top = n.offsetTop; n = n.offsetParent; }; right = left elem.offsetWidth; bottom = top elem.offsetHeight; } else { var rect = elem.getBoundingClientRect(); left = right = doc.documentElement.scrollLeft || doc.body.scrollLeft; top = bottom = doc.documentElement.scrollLeft || doc.body.scrollLeft; left = rect.left; right = rect.right; top = rect.top; bottom = rect.bottom; } return { "left": left, "top": top, "right": right, "bottom": bottom }; }; window.hasClass = function(element, className){ return element.className.match(new RegExp('(\s|^)' className '(\s|$)')); }; window.addClass = function(element, className){ !window.hasClass(element, className)&&(element.className = " " className); }; window.removeClass = function(element, className){ window.hasClass(element, className)&&(element.className = element.className.replace(new RegExp('(\s|^)' className '(\s|$)'),' ')); } })(document); //------------------------------------------------------------ (function(doc,undefined){ var win = this; win.easyTree = function(){ this.init.apply(this,arguments); }; win.easyTree.prototype = { options : { }, init : function(options){ this.deflaut = extend(this.options,options); this.container = options.container; this.data = options.data; //根节点直接在这里生成 if(this.data.length>=1){ var ul = $c('ul',this.container), self = this, li; each(this.data,function(i,o){ li = $c('li',ul); li.className = 'root'; li.innerHTML = '<img src="" class="tvicon-open"><a href="#">' o.name '</a>'; o.child &&self.bulidTree(o.child,li,'t') }); } }, bulidTree : function(data,parent,first){ if(data.length===0) return; var ul = $c('ul',parent), self = this, len = data.length, imgClassName, li; first ? ul.style.paddingLeft = '0px' : ul.style.display = 'none'; each(data,function(i,o){ var isLast = (len-1)===i; li = $c('li',ul); li.className = 'folder' (isLast?'l':''); imgClassName = o.child ? isLast?'tvdash-fl':'tvdash-f' : isLast?'tvdash-tl':'tvdash-t'; li.innerHTML = '<img src="" class="' imgClassName '"><a href="#">' o.name '</a>'; img = li.getElementsByTagName('img')[0]; addListener(img,'click',BindAsEventListener(self,self.openOrClose,li,img)); o.child &&self.bulidTree(o.child,li); }); }, openOrClose : function(e,li,img){ var ul = li.getElementsByTagName('ul')[0]; if(ul){ ul.style.display = ul.style.display === 'none'?'':'none'; var name = img.className, is = img.className.indexOf('open')>-1; img.className = is?name.replace('-open',''):name '-open'; } } } })(document); window.onload = function(){ var i = 0; var data = [{id:i,name:'根节点',child:[]}]; while(i<100){ i ; data[0].child.push({id:i,name:'节点' i,child:[ {id:i*10 1,name:'节点' i '-1',child:[ {id:i*11 1,name:'节点' i '-1-2'}, {id:i*11 2,name:'节点' i '-1-3'}, {id:i*11 3,name:'节点' i '-1-4'} ]}, {id:i*10 2,name:'节点' i '-2',child:[ {id:i*11 4,name:'节点' i '-2-2'}, {id:i*11 5,name:'节点' i '-2-3'}, {id:i*11 6,name:'节点' i '-2-4'} ]}, {id:i*10 3,name:'节点' i '1-3'} ]}); } var t = new Date().getTime(); new easyTree({ container : $$('demo'), data : data }); $$('sss').innerHTML ='一共1000个节点 共耗时:' (new Date().getTime()-t) '毫秒' } </script> </body> </html>

2、

上面只是一个简单的树,但是树应该是有input的,并且能够选中。记录选中能够开打任何节点,能够删除,不能够编辑、保存。说一下我在这里怎么完成上面的功能。选中应该是比较麻烦的,因为选中了一个节点,要让他所有的子节点都选中,他的父节点也有可能要选中(如果同级的都是选中状态的)。接着他的父的父也有可能要选中,所以设计到很多的查找,当生成一个li的时候,给li一个属性:

复制代码 代码如下:

   li.child.push({
                    li    : li,
                    input : isInput ?$q('input',li)[0]:undefined,
                    data  : o
                });

  var LeaveFunext = function(t,f){for(var p in f){t[p]=f[p]} return t};
  var IE = 'v' == 'v';
  var contains = function(wrap,child){
  if(IE) return wrap.contains(child);
  while(child && typeof(child.parentNode) != "undefind"){
  if(wrap == child) return true;
  child = child.parentNode;
}
return false;
  };
  var LeaveFun = function(o){
  var _o = typeof o =="string" ? document.getElementById(o) : o;
  return this == window ? new LeaveFun(_o):LeaveFunext(_o, LeaveFun.prototype);
  };
  LeaveFun.prototype = {
  mouseleave : function(fn){
  if(IE){
  this.attachEvent('onmouseleave',fn);
  }else{
this.addEventListener('mouseout',function(e){
tar = e.relatedTarget;
if(!contains(this, tar)){
fn.call(this);
}
  }, false);
  }
  return this;
  }
  };
  //调用
  LeaveFun('share_customerdiv').mouseleave(function(){document.getElementById('share_customerdiv').style.display ='none';})

记录下他下一级(是下一级 不是所有的子 )的所有的input 和li同时记录父的li 和 input:

3、最简单,但在部分系统上会有轻微闪烁。

   li.parent = {
                    li    : parent,
                    input : isInput ?$q('input',parent)[0]:undefined
                };

复制代码 代码如下:

这样查找起来很方便,但是内存就要用的多些了。

<div style="z-index: 11; " onmouseout="this.style.display='none'" onmouseover="this.style.display='block'" >
<b class="STYLE19">更多此人的...</b>
<a class="STYLE8" >留言板</a>
<a class="STYLE8" >好友</a>
<a class="STYLE8"></a>
</div>

<!DOCTYPE html> <html xmlns="; <head> <meta http-equiv="Content-Type" content="text/html; charset=gb-2312" /> <title>easytree</title> <style type="text/css"> body{font:12px/1.5 '宋体',tahoma;} ul,li{ list-style: none outside none; margin: 0; overflow: hidden; padding: 0; } #demo span{ background: url("../../images/201202/icon.png") no-repeat scroll 0 0 transparent; border: medium none; height: 20px; vertical-align: top; width: 20px; display :inline-block; } #demo .root{ margin-left: -20px; } #demo .root input{ vertical-align: middle; } #demo ul{ padding-left: 20px; } #demo .folder{ background: url("../../images/201202/i.gif") repeat-y scroll 0 21px transparent; } #demo img{ background: url("../../images/201202/icon.png") no-repeat scroll 0 0 transparent; border: medium none; height: 20px; vertical-align: top; width: 20px; } #demo .tvicon-open{ background-position: -160px -40px; } #demo .tvdash-f{ background-position: -240px -40px; } #demo .tvdash-f-open{ background-position: -200px -40px; } #demo .tvdash-fl{ background-position: -100px -40px; } #demo .tvdash-fl-open{ background-position: -80px -40px; } #demo .tvdash-t{ background-position: -180px -40px; } #demo .tvdash-tl{ background-position: -60px -40px; } #demo .tvicon-f{ background-position: -120px -40px; } #demo .tvicon-f-open{ background-position: -140px -40px; } #demo .tvicon-tl{ background-position: -220px -40px; } </style> </head> <body> <div id='sss'></div> <div> 输入id值<br> <input value='101' type="text" id='v'> <input value='展开节点'type="button"onClick="ch(document.getElementById('v').value)"><br><br> 返回的是节点id值 也可以是主键值 <input value='查看有多少节点被选中了'type="button"onClick="ss(this.value)"> <br> </div> <div id='demo'></div> <script> (function(doc,undefined){ var window = this; window.Sys = function (ua){ var b = { ie: /msie/.test(ua) && !/opera/.test(ua), opera: /opera/.test(ua), safari: /webkit/.test(ua) && !/chrome/.test(ua), firefox: /firefox/.test(ua), chrome: /chrome/.test(ua) },vMark = ""; for (var i in b) { if (b[i]) { vMark = "safari" == i ? "version" : i; break; } } b.version = vMark && RegExp("(?:" vMark ")[\/: ]([\d.] )").test(ua) ? RegExp.$1 : "0"; b.ie6 = b.ie && parseInt(b.version, 10) == 6; b.ie7 = b.ie && parseInt(b.version, 10) == 7; b.ie8 = b.ie && parseInt(b.version, 10) == 8; return b; }(window.navigator.userAgent.toLowerCase()); window.Sys.ie6&&doc.execCommand("BackgroundImageCache", false, true); window.$$ = function(Id){ return doc.getElementById(Id); }; window.$q = function(name,parent){ return parent.getElementsByTagName(name); }; window.$c = function(name,parent){ var elem = typeof name==='object'?name:doc.createElement(name); parent&&parent.appendChild(elem); return elem; }; window.addListener = function(element,e,fn){ !element.events&&(element.events = {}); element.events[e]&&(element.events[e][addListener.guid ]=fn)||(element.events[e] = {'0':fn}); element.addEventListener?element.addEventListener(e,fn,false):element.attachEvent("on"

发现它的触发太敏感,当经过层内文字链时,即触发onmousetout事件,功能不能正常显示,经过一番搜索,整理出来,供大家参考。...

  • e,fn); }; window.addListener.guid = 1; window.removeListener = function(element,e,fn){ var handlers = element.events[e],type; if(fn){ for(type in handlers) if(handlers[type]===fn){ element.removeEventListener?element.removeEventListener(e,fn,false):element.detachEvent("on"
  • e,fn); delete handlers[type]; } }else{ for(type in handlers){ element.removeEventListener?element.removeEventListener(e,handlers[type],false):element.detachEvent("on"
  • e,handlers[type]); delete handlers[type]; } } }; window.setStyle = function(e,o){ if(typeof o=="string") e.style.cssText=o; else for(var i in o) e.style[i] = o[i]; }; var slice = Array.prototype.slice; window.Bind = function(object, fun) { var args = slice.call(arguments).slice(2); return function() { return fun.apply(object, args); }; }; window.BindAsEventListener = function(object, fun,args) { var args = slice.call(arguments).slice(2); return function(event) { return fun.apply(object, [event || window.event].concat(args)); } }; //copy from jQ window.extend = function(){ var target = arguments[0] || {}, i = 1, length = arguments.length, deep = true, options; if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; i = 2; } if ( typeof target !== "object" && Object.prototype.toString.call(target)!="[object Function]") target = {}; for(;i<length;i ){ if ( (options = arguments[ i ]) != null ) for(var name in options){ var src = target[ name ], copy = options[ name ]; if ( target === copy ) continue; if ( deep && copy && typeof copy === "object" && !copy.nodeType ){ target[ name ] = arguments.callee( deep, src || ( copy.length != null ? [ ] : { } ), copy ); } else if(copy !== undefined) target[ name ] = copy; } } return target; }; //copy from jQ window.each = function ( object, callback, args ) { var name, i = 0, length = object.length; if ( args ) { args = Array.prototype.slice.call(arguments).slice(2); if ( length === undefined ) { for ( name in object ) if ( callback.apply( object[ name ],[name,object[ name ]].concat(args) ) === false ) break; } else for ( ; i < length; i ) if ( callback.apply( object[ i ],[i,object[ i ]].concat(args)) === false ) // break; } else { if ( length === undefined ) { for ( name in object ) if ( callback.call( object[ name ], name, object[ name ] ) === false ) break; } else for ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[ i] ){} } return object; }; window.currentStyle = function(element){ return element.currentStyle || doc.defaultView.getComputedStyle(element, null); }; window.objPos = function(elem){ var left = 0, top = 0, right = 0, bottom = 0,doc = elem ? elem.ownerDocument : doc; if ( !elem.getBoundingClientRect || window.Sys.ie8 ) { var n = elem; while (n) { left = n.offsetLeft, top = n.offsetTop; n = n.offsetParent; }; right = left elem.offsetWidth; bottom = top elem.offsetHeight; } else { var rect = elem.getBoundingClientRect(); left = right = doc.documentElement.scrollLeft || doc.body.scrollLeft; top = bottom = doc.documentElement.scrollLeft || doc.body.scrollLeft; left = rect.left; right = rect.right; top = rect.top; bottom = rect.bottom; } return { "left": left, "top": top, "right": right, "bottom": bottom }; }; window.hasClass = function(element, className){ return element.className.match(new RegExp('(\s|^)' className '(\s|$)')); }; window.addClass = function(element, className){ !window.hasClass(element, className)&&(element.className = " " className); }; window.removeClass = function(element, className){ window.hasClass(element, className)&&(element.className = element.className.replace(new RegExp('(\s|^)' className '(\s|$)'),' ')); } })(document); //------------------------------------------------------------------------------------ (function(doc,undefined){ var win = this, primary; win.easyTree = function(){ this.init.apply(this,arguments); }; win.easyTree.prototype = { options : { primary : 'id', isInput : false, isIco : false }, init : function(options){ this.deflaut = extend(this.options,options); this.container = options.container; //数据源 形式{id:data[i]} this.data={}; //被勾选的项 this.selected = {}; //根节点直接在这里生成 if(options.data.length>=1){ primary = this.deflaut.primary; var frag=document.createDocumentFragment() var ul = $c('ul',frag),//this.container self = this, input = this.deflaut.isInput?'<input type="checkbox">':'', li; each(options.data,function(i,o){ li = $c('li',ul); li.className = 'root'; li.innerHTML = [ '<span class="tvicon-open"></span>', input, '<a href="#">' o.name '</a>' ].join(''); li.setAttribute('primary',o[primary]); self.data[o[primary]] = {elem:li,data:o}; o.child &&self.bulidTree(o.child,li,'t'); }); //只绑定一个节点 展开和checkedbox判断都在里面 addListener(ul,'click',BindAsEventListener(self,self.operation)); this.container.appendChild(frag); } }, bulidTree : function(data,parent,first){ if(data.length===0) return; var ul = $c('ul',parent), self = this, len = data.length, isInput = this.deflaut.isInput, input = isInput?'<input type="checkbox">':'', isIco = this.deflaut.isIco, imgClassName, img, li; first ? ul.style.paddingLeft = '0px' : ul.style.display = 'none'; parent.child = []; each(data,function(i,o){ var isLast = (len-1)===i, ico = isIco ? o.child ? '<span class="tvicon-f"></span>' : '<span class="tvicon-tl"></span>' : ''; li = $c('li',ul); li.className = 'folder' (isLast?'l':''); imgClassName = o.child ? isLast?'tvdash-fl':'tvdash-f' : isLast?'tvdash-tl':'tvdash-t'; li.innerHTML = [ '<span class="' imgClassName '"></span>', ico, input, '<a href="#">' o.name '</a>' ].join(''); //当前li保存父li的相关信息 只是一个对象 li.parent = { li : parent, input : isInput ?$q('input',parent)[0]:undefined }; //当前li保存子li的相关信息 是一个数组 parent.child.push({ li : li, input : isInput ?$q('input',li)[0]:undefined, data : o }); li.setAttribute('primary',o[primary]); li.getElementsByTagName('span')[0].setAttribute('mark','mark'); self.data[o[primary]] = {elem:li,data:o}; o.child &&self.bulidTree(o.child,li); }); }, operation : function(e){ var elem = e.srcElement || e.target, nodeName = elem.nodeName.toLocaleLowerCase(); /*显示隐藏子菜单*/ if((nodeName==='span'&&elem.getAttribute('mark'))||(nodeName==='a')){ var li = elem.parentNode, ul = $q('ul',li)[0], img = $q('span',li)[0], ico = $q('span',li)[1]; if(ul){ ul.style.display = ul.style.display === 'none'?'':'none'; var name = img.className, is = img.className.indexOf('open')>-1; img.className = is?name.replace('-open',''):name '-open'; if(ico){ ico.className = is?ico.className.replace('-open',''):ico.className '-open'; } } }; //选中checkedbox的时候的相应的操作 if(nodeName==='input'){ var isCheck = elem.checked, li = elem.parentNode, ul = $q('ul',li)[0], id = li.getAttribute('primary'), //该元素的索引是否已经添加到了 this.selected中 isIn = id in this.selected; //操作this.selected 从里面添加或者删除 isCheck ? !isIn &&(this.selected[id]=id) : isIn &&delete this.selected[id]; this.findChild(li,isCheck); this.findParent(li,isCheck); } }, findParent : function(child,b){ if(!child.parent) return; var parentLi = child.parent.li, id = parentLi.getAttribute('primary') isAll = true; if(b){ //看他父下面的所有li是不是都是选中状态的 each(parentLi.child,function(i,o){ if(!o.input.checked){ isAll = false; return false; } }); //如果都是选中状态 //继续查找他的父 if(isAll){ child.parent.input.checked = true; !(id in this.selected) &&(this.selected[id] = id); this.findParent(parentLi,b); } }else{ if(child.parent.input.checked){ child.parent.input.checked = false; id in this.selected && delete this.selected[id]; this.findParent(parentLi,b); } } }, /* 查找子节点 将所有没有选中的字节点选中 并放到this.selected里面去 或者取消所有的子节点 */ findChild : function(parent,b){ if(!parent.child) return; var self = this; b ? each(parent.child,function(i,o){ if(!o.input.checked){ o.input.checked = true; !(o.data[primary] in self.selected) &&(self.selected[o.data[primary]] = o.data[primary]); o.li.child &&self.findChild(o.li,b); } }) : each(parent.child,function(i,o){ if(o.input.checked){ o.input.checked = false; o.data[primary] in self.selected && delete self.selected[o.data[primary]]; o.li.child &&self.findChild(o.li,b); } }); }, getAllSelect : function(){ var arr = [], id; for(id in this.selected) arr.push(id); return arr.join(',') }, openNode : function(id){ if(id in this.data){ var li = this.data[id].elem, parent = li.parentNode, img, ico; while(parent.style.display==='none'){ parent.style.display = ''; li = li.parent.li; img =$q('span',li)[0]; ico =$q('span',li)[1]; img.className=img.className '-open'; ico &&(ico.className=ico.className '-open'); parent = li.parentNode; } } } } })(document); window.onload = function(){ var i = 0,j=100; var data1 = [{id:i,name:'根节点',child:[]}]; while(i<100){ i ; data1[0].child.push({id:i,name:'节点' i,child:[ {id: j,name:'节点' i '-1',child:[ {id: j,name:'节点' i '-1-1'}, {id: j,name:'节点' i '-1-2'}, {id: j,name:'节点' i '-1-3'} ]}, {id: j,name:'节点' i '-2',child:[ {id: j,name:'节点' i '-2-1'}, {id: j,name:'节点' i '-2-2'}, {id: j,name:'节点' i '-2-3'} ]}, {id: j,name:'节点' i '-3-1'} ]}); } var t = new Date().getTime(); window.tt= new easyTree({ container : $$('demo'), isInput : true, isIco : true, data : data1 }); //alert(new Date().getTime()-t1) $$('sss').innerHTML ='一共1000个节点 共耗时:' (new Date().getTime()-t) '毫秒' } function ch(v){ tt.openNode(v) } function ss(){ alert(tt.getAllSelect()); } </script> </body> </html>

基本能达到要求了。

dhtree 梅花雪树对比了下,都差不多。 (ps感觉比dhtree快点,跟梅花雪树差不多,...

本文由9159.com发布于前端,转载请注明出处:原来那位老兄是用一般方法写成的无限级折叠菜

关键词: 9159.com

上一篇:首先必须理解Javascript特殊的变量作用域
下一篇:没有了