⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wztree.js

📁 javascript实现的节点树,无限分级 还带有详细的使用说明,
💻 JS
字号:
//@charset "utf-8"; //you could change as gb2312
(function() {if (!window.XTree) window.XTree = {n:1};})();

/**
 * @function: tree[edit&&show]
 * @filename: tree.js
 * @lang[l] : 0:zh_CN; 1:us_EN, ...
 * @style[s]: yyyy-MM-dd
 * @author  : liujy
 * @mailto  : liujy.mail (at) gmail.com
 * @version : v1.0
 * @create  : 2008-12-12
 * @modify  : 2008-12-20
 * @memo    : node name has special char may be a problem ~
 */
var lang = 0;
var datas = '1,0,根结点;2,1,结点2;3,1,结点3;4,2,结点4;5,2,结点5;6,5,结点6;7,5,结点7;20,5,结点20;8,7,结点8;A,7,结点A;9,8,结点9;11,5,结点K;12,11,结点L;13,11,结点Q;15,2,结点U;16,5,结点K;18,15,结点H;19,18,结点X;';

function _$(s) {return document.getElementById(s);}
function _t(s) {return (s?(''+s).replace(/(^\s*)|(\s*$)/g, ""):"");}
function _b(s) {return (s?(''+s).replace(/[\u0391-\uFFE5]/g, "**").length:0);}
function _i(s) {var n=0; try {n=parseInt(_t(s),10); n=(isNaN(n)?0:n);} catch(e){ } return n;}
function _e(s) {return escape(_t(s)).replace(/\%u/gi, "!").replace(/\%/gi, "|"); }
function _u(s) {return unescape(_t(s).replace(/\|/gi, "%").replace(/!/gi, "%u")); }

function WzTree(datas)
{
  w = this;
  w.n = window.XTree.n++;
  var vmaps = window.XTree[w.n] || {};
  vmaps.x = w.n;
  w.vm = vmaps;

  w._xy = function(e)
  {
    var x = e.offsetLeft;
    var y = e.offsetTop;
    while(e = e.offsetParent)
    {
      x += e.offsetLeft;
      y += e.offsetTop;
    }
    return [x, y];
  };

  w.setTreeAreaWH = function(wh)
  {
    if (!w.vm.t) return;
    w.vm.t.style.width = wh[0];
    w.vm.t.style.height = wh[1];
  };

  w.setTreeLocaXY = function(xy)
  {
    if (!w.vm.t) return;
    w.vm.t.style.left = xy[0];
    w.vm.t.style.top = xy[1];
  };

  w.setTreeLoca = function(obj) {w.setTreeLocaXY(w._xy(obj));};

  w.setTreeData = function(str)
  {
    if (!w.vm.t) return;
    var obj = w.vm.t;
    w.vm = dataToMap(str||'1,0,根结点');
    w.vm.t = obj;
  };

  w.appendNode = function(vo,mark)
  {
    if (!vo || _t(vo[2])=='') return ;
    if (!w.vm.n) { alert("从哪里添加"); return; }
    if (mark && w.vm.n==w.vm.r) { alert("根结点仅能添加下级"); return; }

    var nid = _i(w.vm['mxid'])+1;
    w.vm['mxid'] = nid+1;
    var cid = pni(w.vm.n.id);
    var pid,subs;
    if (mark)
    {
      pid = w.vm[cid][1]; //同级
      subs = _t(w.vm['s'+pid]).replace(','+cid+',',','+cid+','+nid+',');
    }
    else
    {
      pid = cid; //下级
      subs = ','+nid+_t(w.vm['s'+pid]);
    }
    w.vm['s'+nid] = ',';
    w.vm['s'+pid] = subs;
    var lys = _t(w.vm[pid][3])+pid+'.';
    w.vm[nid] = [nid,pid,_t(vo[2]),lys,'0','v4','v5~n'];
    var len = w.vm[cid].length;
    for (var i=04; i<len; i++) w.vm[nid][i]= _t(vo[i]);
    w.vm["nids"] = _t(w.vm["nids"]).replace(','+cid+',',','+cid+','+nid+',');
    w.show(); //re-paint tree ~
    
    w.vm.n.style.backgroundColor = 'transparent';
    w.vm.n = _$(w.n+'_'+nid);
    w.vm.n.style.backgroundColor = '#66c';
  };

  w.modifyNode = function(vo)
  {
    if (!w.vm.n) { alert('修改哪个结点'); return; }
    var id = pni(w.vm.n.id);
    var len = w.vm[id].length;
    for (var i=0; i<len; i++) w.vm[id][i]=(_t(vo[i])==''?w.vm[id][i]:_t(vo[i]));
    w.vm.n.getElementsByTagName("span")[0].innerHTML = w.vm[id][2];
  };

  w.deleteNode = function()
  {
    if (!w.vm.n) { alert('删除哪个结点'); return; }
    if (w.vm.r && w.vm.r==w.vm.n) { alert('根结点不能删除'); return; }
    var nxt = w.vm.n.nextSibling;
    var num = ((nxt && ',has,cls,'.indexOf(nxt.className+',')>0)?nxt.getElementsByTagName("span").length:0);
    var msg = '确认要删除选中的结点'+(num>0?'[包括子结点]':'')+'吗?';
    if (confirm(msg))
    {
      var cid = pni(w.vm.n.id);
      var pid = w.vm[cid][1];
      var subs = w.vm['s'+pid];
      w.vm['s'+pid] = subs.replace(','+cid+',', ',');
      w.vm['nids'] = rebuildNids(w.vm);
      w.show();
    }
  };

  w.treeToDataStr = function()
  {
    var arr = strToArr(w.vm['nids']);
    var kids = '', len = arr.length;
    for (var i=0; i<len; i++) 
      kids += w.vm[arr[i]][0]+','+w.vm[arr[i]][1]+','+w.vm[arr[i]][2]+';';
    return kids; //as datas 
  };

  w.treeToData = function()
  {
    var arr = strToArr(w.vm['nids']);
    var kids = '', len = arr.length;
    for (var i=0; i<len; i++) kids += _e(w.vm[arr[i]].toString())+';';
    return kids;
  };

  w.nodeToData = function()
  {
    if (!w.vm.n) return '';
    var arr = w.vm[pni(w.vm.n.id)];
    return _e(arr.toString());
  };

  w.shrinkTreeNodeByIds = function(nids)
  {
    //if (!w.vm.t || !nids) return;
    var arr = strToArr(nids);
    var len = arr.length;
    for (var i=0; i<len; i++)
    {
      var obj,els=_$(w.n+'_'+arr[i]).getElementsByTagName("span");
      obj = (els?els[0].previousSibling:null);
      if (obj && obj.className!='fo') obj = obj.previousSibling;
      if (obj && obj.className=='fo') iconOnOff(w.vm, obj.previousSibling);  
    }
  };

  w.revsTreeNodeByIds = function(nids)
  {
    //if (!w.vm.t || !nids) return;
    var arr = strToArr(nids);
    var len = arr.length;
    for (var i=0; i<len; i++)
    {
      var obj,els=_$(w.n+'_'+arr[i]).getElementsByTagName("span");
      obj = (els?els[0].previousSibling:null);
      if (obj && ',fo,fc,'.indexOf(obj.className+',')<1) obj = obj.previousSibling;
      if (obj && ',fo,fc,'.indexOf(obj.className+',')>0) iconOnOff(w.vm, obj.previousSibling);  
    }
  };

  w.show = function()
  {
    if (!w.vm.t) return;
    w.vm.t.innerHTML = mapToHtml(w.n,w.vm);
    bindNodeEvent(w.vm, w.vm.t);
    w.vm.r = _$(w.n+'_'+w.vm["root"]);
    w.vm.t.style.display = 'block';
    w.vm.x = w.n; //XXX
  };

  init = function()
  {
    if (!_$("tree"+w.n))
    {
      var tree = createDivElement("tree"+w.n, "pane");
      document.body.appendChild(tree);
      w.vm = dataToMap(datas||'1,0,根结点');
      w.vm.t = tree; 
    }
  };
  init();
}

function createDivElement(id,cls)
{
  var ele = document.createElement("div");
  if (id&&id.length>1) ele.setAttribute('id',id);
  ele.className = cls;
  return ele;
}

//ok~
function rebuildNids(vals, id)
{
  var id = _t(vals['root']);
  var kids = ','+id+',';
  var arr, waits = uniteArr(null, strToArr(vals['s'+id]));
  var wl = (waits?waits.length:0);
  while (wl>0)
  {
    id = _t(waits[--wl]);
    waits.length = wl;
    if (_i(id)>0) kids += id+',';

    arr = strToArr(vals['s'+id]);
    if (arr.length>0) waits = uniteArr(waits, arr);
    wl = waits.length;
  }
  return kids;
}

// ok ~ 
function pni(id)
{
  //id:km+"_"+id >> peelNodeId --> pni
  var pos = (id?id.lastIndexOf('_'):0);
  return (pos<1?'':id.substring(pos+1));
}

//ok~
function rowClick(vals, obj)
{
  if (vals.n) vals.n.style.backgroundColor="transparent";
  vals.n=obj;
  obj.style.backgroundColor="#99c";//here add your self method
  if (typeof(nodeRowClick)=='function') nodeRowClick([vals[pni(obj.id)],[vals['s'+pni(obj.id)]]]);
}

//ok~
function rowOver(vals, obj)
{
  if (vals.n!=obj) obj.style.backgroundColor="#ccc";
}

//ok~
function rowOut(vals, obj)
{
  if (vals.n!=obj) obj.style.backgroundColor="transparent";
}

//ok~
function textClick(vals, obj)
{
  var id = pni(obj.parentNode.id);
  if (typeof(nodeTextClick)=='function') nodeTextClick([vals[id],[vals['s'+id]]]);
}

// ok ~ 
function bindNodeEvent(vals, obj)
{
  if (!obj) return;
  var els = obj.getElementsByTagName("span");
  var len = (els?els.length:0);
  for (var i=0; i<len; i++)
  {
    var row = els[i].parentNode;
    els[i].ondblclick = function() { textClick(vals, this); }
    row.onmouseover = function() { rowOver(vals, this); }
    row.onmouseout = function() { rowOut(vals, this); }
    row.onclick = function() { rowClick(vals, this); }
    
    var dir = els[i].previousSibling;
    if (',fo,fc,'.indexOf(dir.className+',')<1) dir = dir.previousSibling;
    if (',fo,fc,'.indexOf(dir.className+',')>0)
    {
      var hub = dir.previousSibling;
      hub.onclick = function() { iconOnOff(vals, this); }
      dir.ondblclick = function() { iconOnOff(vals, this.previousSibling); };
    }
  } //end for
  if (typeof(customTreeView)=='function') customTreeView(vals.t); //XXX
}

//ok~
function isEnd(vals, lid)
{
  var pid = _t(vals[lid][1]);
  var subs = strToArr(_t(vals['s'+pid]));
  return (lid==_t(subs[subs.length-1]));
}

//ok ~ 
function calcSeal(vals, id, nid)
{
  var seal = '';
  var pid = _i(vals[id][1]);
  var kpid = _i(vals[nid][1]);
  while (pid>0 && pid!=kpid)
  {
     seal += '</div>';
     pid = _i(vals[pid][1]);
  }
  return seal; 
}

//ok ~ 
function calcGrid(vals, id)
{
  var grd='',als=strToArr(_t(vals[id][3]),'.'); //id~lys [1..len-1]
  for (var i=1; i<als.length; i++) grd += '<div class="'+(isEnd(vals,_t(als[i]))?'grid':'grdv')+'"></div>';
  return grd;
}

//ok ~ 
function mapToHtml(mk, vals)
{
  var htm = '';
  var id = _t(vals['root']); 
  var rec = vals[id] || [];
  var subs = strToArr(vals['s'+id]);

  //root htm
  htm += '<div id="'+mk+'_'+id+'" class="row">';
  if (subs.length<1)
  {
    htm += '<div class="grid"></div><div class="leaf"></div><span>'+_t(rec[2])+'</span></div>';
    return htm;
  }
  htm += '<div class="g2"></div><div class="fo"></div><span>'+_t(rec[2])+'</span></div><div class="has">';

  //node htm
  var waits = uniteArr(null, subs);
  var wl = (waits?waits.length:0);
  while (wl>0)
  {
    id = _t(waits[--wl]);
    waits.length = wl;

    rec = vals[id] || []; //open pid name lys ...
    var tail = isEnd(vals,id);
    subs = strToArr(vals['s'+id]);

    htm += '<div id="'+mk+'_'+id+'" class="row">';
    if (subs.length<1)
    {
      htm += '<div class="grid"></div>' + calcGrid(vals, id);
      htm += '<div class="'+(tail?'g3':'gt')+'"></div><div class="leaf"></div><span>'+_t(rec[2])+"-"+_t(rec[0])+'</span></div>';
      if (tail || wl<1) htm += '</div>';
      htm += ((!tail || wl<1)?'':calcSeal(vals, vals[id][1], waits[wl-1]));
    }
    else
    {
      waits = uniteArr(waits, subs);
      htm += '<div class="grid"></div>' + calcGrid(vals, id);
      htm += '<div class="'+(tail?'g5':'g7')+'"></div><div class="fo"></div><span>'+_t(rec[2])+"-"+_t(rec[0])+'</span></div><div class="has">';
    }
    wl = waits.length;
  }
  return htm;
}

function iconOnOff(vals,obj)
{
  var cls = obj.className;
  if (',g1,g2,g4,g5,g7,g8,'.indexOf(cls+',')<1) return ;
  vals[pni(obj.parentNode.id)][4] = (obj.nextSibling.className=='fo'?'1':'0');
  if (cls=='g7')
  {
    obj.className = 'g8';
    obj.nextSibling.className = 'fc';
    obj.parentNode.nextSibling.className = 'cls';
  }
  else if (cls=='g8')
  {
    obj.className = 'g7';
    obj.nextSibling.className = 'fo';
    obj.parentNode.nextSibling.className = 'has';
  }
  else if (cls=='g5')
  {
    obj.className = 'g4';
    obj.nextSibling.className = 'fc';
    obj.parentNode.nextSibling.className = 'cls';
  }
  else if (cls=='g4')
  {
    obj.className = 'g5';
    obj.nextSibling.className = 'fo';
    obj.parentNode.nextSibling.className = 'has';
  }
  else if (cls=='g2')
  {
    obj.className = 'g1';
    obj.nextSibling.className = 'fc';
    obj.parentNode.nextSibling.className = 'cls';
  }
  else if (cls=='g1')
  {
    obj.className = 'g2';
    obj.nextSibling.className = 'fo';
    obj.parentNode.nextSibling.className = 'has';
  }
}

//ok
function dataToMap(str)
{
  var vals={};
  var maps={};
  var id=0,rid=0,pid=0;
  var arr,recs=str.split(";");
  var max=0,ids=',',len=recs.length;
  for (var i=0; i<len; i++)
  {
    if (_b(recs[i])<3) continue;
    arr = _t(recs[i]).split(',');

    id = _i(arr[0]); //here attention ~ isNaN(id)
    if (id<1 || ids.indexOf(','+id+',')>-1 || arr.length<3) continue;
    max = (max<id?id:max);
    ids += id+',';
    pid = _i(arr[1]);
    vals[''+id] = [_t(arr[0]),_t(arr[1]),_t(arr[2]),null,'0','v4','v5~n']; //arr[4~n]
    var subs = vals['s'+pid] || ',';
    if (subs.indexOf(','+id+',')<0) vals['s'+pid] = subs+id+',';
    maps[''+id] = ''+pid;
  }
  vals["nids"] = ids;
  vals["mxid"] = max;
  vals["root"] = _t(vals['s0']).split(',')[1];

  arr = ids.split(',');
  len = arr.length-1;
  for (var i=1; i<len; i++)
  {
    id = _i(arr[i]);
    pid = _i(maps[''+id]);
    var lys='.',test=true;
    while (test && pid>0)
    {
      if (vals[''+id][3] || lys.indexOf('.'+pid+'.')>-1) test = false;
      lys = (vals[''+id][3]?vals[''+id][3]+lys:'.'+pid+lys);
      if (test) pid = _i(maps[''+pid]);
    }
    vals[''+id][3] = lys; 
  }
  maps = null;
  return vals;
}

//ok~
function strToArrLen(str,ch)
{
  var s = (str?_t(str):'');
  var c = (ch?_t(ch):',');
  var p = s.indexOf(c);
  if (p==0) s = s.substring(1); 
  p = s.lastIndexOf(c);
  if (p==s.length-1) s = s.substring(0, p);
  if (s=='') return [];
  return s.split(c).length;
}

//ok~
function strToArr(str,ch)
{
  var s = (str?_t(str):'');
  var c = (ch?_t(ch):',');
  var p = s.indexOf(c);
  if (p==0) s = s.substring(1); 
  p = s.lastIndexOf(c);
  if (p==s.length-1) s = s.substring(0, p);
  if (s=='') return [];
  return s.split(c);
}

//ok~
function uniteArr(arr1, arr2)
{
  var arr = (arr1?arr1:[]);
  var len = arr2.length-1;
  if (!arr2 || len<0) return arr1;
  for (var i=len; i>-1; i--) arr[arr.length] = arr2[i]; 
  return arr;
}

//**几种展开状态**
//1.仅根展开
//2.全部展开
//3.某几项展开
//4.仅根合并
//5.除根外全部合并
//6.某几项合并
//**几种编辑状态**
//1.新增[添加同级,添加下级]
//2.修改[名称]
//3.删除[是否允许删除有子结点的点,提供全部可删除]
//4.保存

//考虑: dataToHTML时用字串,减少重整JS数组的时间,或者依次输出
//规定:父结点为零的是根结点,并且只能有一个,避免loop引用 用数组扩展性好一些

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -