dtree 网页树状菜单及传递对象集合到js内,动态生成节点
最近要做一个联系人的选择框,选择联系人后,将联系人的手机号添加到网页的输入框,可以支持复选框。在winform端,树状菜单是非常有用的,实现这个是非常便捷的,所以我想到在页面放入一个树状菜单的。我选择了dtree这个工具,网络上还有很多方法实现页面树状菜单的,不过我觉得这个比较好用的,而且配置比较简单,运用上上手很快。dtree是纯js的,所以不用导入jar包,并且配置只要在js内配置就好了。而且现在网络上有很多高手修改后的改良版,加了checkbox,更加方便。在开发过程中,最难的就是数据的交互的,因为dtree是纯js的,所以不存在和后台交互的方法,我的办法是先通过后台交互,将数据传递到页面,然后再传递到js内。后台传递到页面的数据我拼接成一个字符串,然后在js内切割,将数据整合成数组。
后台数据处理代码:
Codepublic String GetLinkManByDID(){ try { directories = this.directoryService.GetAllDirecoty(); selectlinkMans = this.linkManService.GetAllLinkMans(); String direStringstring = ""; String linkString = ""; for (int i = 0; i < directories.size(); i++) { if (i<directories.size()-1) { direStringstring+=directories.get(i).getID()+"-"+directories.get(i).getDirectoryName()+"+"; } else { direStringstring+=directories.get(i).getID()+"-"+directories.get(i).getDirectoryName(); } } for (int i = 0; i < selectlinkMans.size(); i++) { if (i<selectlinkMans.size()-1) { linkString+=selectlinkMans.get(i).getDirectory().getID()+"-"+selectlinkMans.get(i).getName()+"-"+selectlinkMans.get(i).getPhoneNum()+"+"; } else { linkString+=selectlinkMans.get(i).getDirectory().getID()+"-"+selectlinkMans.get(i).getName()+"-"+selectlinkMans.get(i).getPhoneNum(); } } ActionContext.getContext().getSession().put("directories", direStringstring); ActionContext.getContext().getSession().put("allLinkMans", linkString); } catch (Exception e) { e.printStackTrace(); } return SUCCESS; }
ActionContext.getContext().getSession().put(key, value)
然后页面得到数据:
<script type="text/javascript">
var linkmans= [];
var dires = [];
//linkmans = "${directories}".replace('[','').replace(']','').split(',');
linkmans="${allLinkMans}".split(',');
dires = "${directories}".split(',');
treeload(linkmans[0],dires[0]);
</script>
treeload 是我自己编写的一个js文件内的方法。
js:
Codefunction treeload(linkmans , dires){ var linklist= String2linklist(linkmans); var direslist = String2direlist(dires); d = new dTree('d','./'); d.config.checkbox=true;//显示checkbox d.config.objValueId='phoneNums'; d.icon.root='images/hr/home.png', d.icon.folder='images/hr/group.gif', d.icon.folderOpen='images/hr/group.gif', d.icon.node='images/hr/nan.gif', d.add(0,-1,'联系人',null); var int = 0; var direids = new Array(); var direpid= new Array(); for ( int; int < direslist.length; int++) { d.add(int+1,0,direslist[int].name,false); direids.push(direslist[int].id); direpid.push(int+1); } d.add(int+1,0,'全部联系人',false); direpid.push(int+1); for ( var int2 = 0; int2 < linklist.length; int2++) { for ( var int3 = 0; int3 < direpid.length-1; int3++) { if(linklist[int2].did==direids[int3]) { int++; d.add(int+1,direpid[int3],linklist[int2].name,false,linklist[int2].phone); } } } for ( var int4 = 0; int4 < linklist.length; int4++) { int++; d.add(int+1,direpid[direpid.length-1],linklist[int4].name,false,linklist[int4].phone); } document.write(d); } function String2linklist(linkmans){ var linkarray = new Array(); var a = linkmans.split('+'); // alert(a[0]); for ( var int = 0; int < a.length; int++) { var b = a[int].split('-'); // alert(b[2]); linkarray.push(new linkman(b[0],b[1],b[2])); } return linkarray; } function String2direlist(dires){ var direlist = new Array(); var a = dires.split('+'); for ( var int = 0; int < a.length; int++) { var b = a[int].split('-'); // alert(b[1]); direlist.push(new dire(b[0],b[1])); } return direlist; } function linkman(Did,name,phone){ this.did = Did; this.name = name ; this.phone=phone; } function dire(id ,name){ this.id= id; this.name = name; }
最后,效果图
我改写的dtree 的js:
Code // Node object function Node(id, pid, name, checked, value, icon ,url, title, target, iconOpen, open) { this.id = id; this.pid = pid; this.name = name; //是否在该节点添加复选框并设置选中状态,true:选中,false:不选中,null:不添加 this.checked = checked==null?null:(checked || false); this.value = value;//增加value属性,选中复选框,输入框内得到的就是这个value值 this.url = url; this.title = title; this.target = target; this.icon = icon; this.iconOpen = iconOpen; this._io = open || false; this._is = false; this._ls = false; this._hc = false; this._ai = 0; this._p; }; // Tree object function dTree(objName, path) { //路径 this.path = path ||''; //加载css文件 this.loadCssFile(this.path+'dtree.css'); this.config = { target : null, folderLinks : true, useSelection : true, useCookies : true, useLines : true, useIcons : true, useStatusText : false, closeSameLevel : false, inOrder : false, //是否显示复选框,true显示,false不显示 checkbox:false, objValueId:'' } this.icon = { root : this.path + 'images/img/base.gif', folder : this.path + 'images/img/folder.gif', folderOpen : this.path + 'images/img/folderopen.gif', node : this.path + 'images/img/page.gif', empty : this.path + 'images/img/empty.gif', line : this.path + 'images/img/line.gif', join : this.path + 'images/img/join.gif', joinBottom : this.path + 'images/img/joinbottom.gif', plus : this.path + 'images/img/plus.gif', plusBottom : this.path + 'images/img/plusbottom.gif', minus : this.path + 'images/img/minus.gif', minusBottom : this.path + 'images/img/minusbottom.gif', nlPlus : this.path + 'images/img/nolines_plus.gif', nlMinus : this.path + 'images/img/nolines_minus.gif' }; this.obj = objName; this.aNodes = []; this.aIndent = []; this.root = new Node(-1); this.selectedNode = null; this.selectedFound = false; this.completed = false; }; //设置选中节点 dTree.prototype.checkedNodes=function(){ if(this.config.objValueId==''){ return; } var val=document.getElementById(this.config.objValueId).value; if(val==''){ return; } val=val.split(','); var o=null; for(var i=0;i<val.length;i++){ o=document.getElementById('cbx_'+this.obj+val[i]); if(o){ o.checked=true; } } }; //实现输入框内自动输入选中项的value值 dTree.prototype.update=function(){ if(this.config.objValueId==''){ return; } var cbx=null,v=[]; // v.push(aa); var ns=this.aNodes; for(var i=0;i<ns.length;i++){ cbx=document.getElementById('cbx_'+this.obj+ns[i].id); if(cbx){ if(cbx.checked){ if(ns[i].pid!='0'){ v.push(cbx.value);//原先是得到节点的id的,换成value,可以实现选中联系人,得到号码。 } } } } document.getElementById(this.config.objValueId).value=v.join(); }; //加载css文件 dTree.prototype.loadCssFile=function (file) { try{ var head=document.getElementsByTagName("head")[0]; var links=head.getElementsByTagName('link'); var i=0; for(var i=0;i<links.length;i++){ if(links[i].getAttribute('href').toLowerCase().indexOf(file.toLowerCase())>-1){ return; } } var f = document.createElement("link"); f.setAttribute("rel", "stylesheet"); f.setAttribute("type", "text/css"); f.setAttribute("href", file); head.appendChild(f); }catch(ex){ alert('加载css文件出错:'+ex.message); } }; // Adds a new node to the node array dTree.prototype.add = function(id, pid, name, checked, value,icon,url, title, target,iconOpen, open) { this.aNodes[this.aNodes.length] = new Node(id, pid, name, checked, value,icon,url, title, target, iconOpen, open); }; // Open/close all nodes dTree.prototype.openAll = function() { this.oAll(true); }; dTree.prototype.closeAll = function() { this.oAll(false); }; // Outputs the tree to the page dTree.prototype.toString = function() { var str = '<div class="dtree" id="dTree_'+this.obj+'">\n'; if (document.getElementById) { if (this.config.useCookies) this.selectedNode = this.getSelected(); str += this.addNode(this.root); } else str += 'Browser not supported.'; str += '</div>'; if (!this.selectedFound) this.selectedNode = null; this.completed = true; return str; }; // Creates the tree structure dTree.prototype.addNode = function(pNode) { var str = ''; var n=0; if (this.config.inOrder) n = pNode._ai; for (n; n<this.aNodes.length; n++) { if (this.aNodes[n].pid == pNode.id) { var cn = this.aNodes[n]; cn._p = pNode; cn._ai = n; this.setCS(cn); if (!cn.target && this.config.target) cn.target = this.config.target; if (cn._hc && !cn._io && this.config.useCookies) cn._io = this.isOpen(cn.id); if (!this.config.folderLinks && cn._hc) cn.url = null; if (this.config.useSelection && cn.id == this.selectedNode && !this.selectedFound) { cn._is = true; this.selectedNode = n; this.selectedFound = true; } str += this.node(cn, n); if (cn._ls) break; } } return str; }; // Creates the node icon, url and text dTree.prototype.node = function(node, nodeId) { var str = '<div class="dTreeNode">' + this.indent(node, nodeId); if (this.config.useIcons) { if (!node.icon) node.icon = (this.root.id == node.pid) ? this.icon.root : ((node.pid==0) ? this.icon.folder : this.icon.node); //node.pid==0 这个条件是我自己改的,如果群组内无人的话,还是用群组的icon,而不是联系人的icon,大家可以自己试试的 if (!node.iconOpen) node.iconOpen = (node._hc) ? this.icon.folderOpen : this.icon.node; if (this.root.id == node.pid) { node.icon = this.icon.root; node.iconOpen = this.icon.root; } str += '<img id="i' + this.obj + nodeId + '" src="' + ((node._io) ? node.iconOpen : node.icon) + '" alt="" />'; } /***添加checkbox显示***/ if(this.config.checkbox&&node.checked!=null){ str += '<input '+ (node.checked?'checked=\"checked\"':'') +' onclick=\"javascript: ' + this.obj + (node._hc &&node.pid != this.root.id?'.o(' + nodeId + ')':'.update()')+';\" type=\"checkbox\" value=\"'+node.value+'\" name=\"cbx_'+this.obj+'\" id=\"cbx_'+ this.obj + nodeId+'\" title=\"'+node.name+'\"\/>'; } if (node.url) { str += '<a id="s' + this.obj + nodeId + '" class="' + ((this.config.useSelection) ? ((node._is ? 'nodeSel' : 'node')) : 'node') + '" href="' + node.url + '"'; if (node.title) str += ' title="' + node.title + '"'; if (node.target) str += ' target="' + node.target + '"'; if (this.config.useStatusText) str += ' onmouseover="window.status=\'' + node.name + '\';return true;" onmouseout="window.status=\'\';return true;" '; if (this.config.useSelection && ((node._hc && this.config.folderLinks) || !node._hc)) str += ' onclick="javascript: ' + this.obj + '.s(' + nodeId + ');"'; str += '>'; } else if ((!this.config.folderLinks || !node.url) && node._hc && node.pid != this.root.id) str += '<a href="javascript: ' + this.obj + '.o(' + nodeId + ');" class="node">'; str += node.name; if (node.url || ((!this.config.folderLinks || !node.url) && node._hc)) str += '</a>'; str += '</div>'; if (node._hc) { str += '<div id="d' + this.obj + nodeId + '" class="clip" style="display:' + ((this.root.id == node.pid || node._io) ? 'block' : 'none') + ';">'; str += this.addNode(node); str += '</div>'; } this.aIndent.pop(); return str; }; // Adds the empty and line icons dTree.prototype.indent = function(node, nodeId) { var str = ''; if (this.root.id != node.pid) { for (var n=0; n<this.aIndent.length; n++) str += '<img src="' + ( (this.aIndent[n] == 1 && this.config.useLines) ? this.icon.line : this.icon.empty ) + '" alt="" />'; (node._ls) ? this.aIndent.push(0) : this.aIndent.push(1); if (node._hc) { str += '<a href="javascript: ' + this.obj + '.o(' + nodeId + ');"><img id="j' + this.obj + nodeId + '" src="'; if (!this.config.useLines) str += (node._io) ? this.icon.nlMinus : this.icon.nlPlus; else str += ( (node._io) ? ((node._ls && this.config.useLines) ? this.icon.minusBottom : this.icon.minus) : ((node._ls && this.config.useLines) ? this.icon.plusBottom : this.icon.plus ) ); str += '" alt="" /></a>'; } else str += '<img src="' + ( (this.config.useLines) ? ((node._ls) ? this.icon.joinBottom : this.icon.join ) : this.icon.empty) + '" alt="" />'; } return str; }; // Checks if a node has any children and if it is the last sibling dTree.prototype.setCS = function(node) { var lastId; for (var n=0; n<this.aNodes.length; n++) { if (this.aNodes[n].pid == node.id) node._hc = true; if (this.aNodes[n].pid == node.pid) lastId = this.aNodes[n].id; } if (lastId==node.id) node._ls = true; }; // Returns the selected node dTree.prototype.getSelected = function() { var sn = this.getCookie('cs' + this.obj); return (sn) ? sn : null; }; // Highlights the selected node dTree.prototype.s = function(id) { if (!this.config.useSelection) return; var cn = this.aNodes[id]; if (cn._hc && !this.config.folderLinks) return; if (this.selectedNode != id) { if (this.selectedNode || this.selectedNode==0) { eOld = document.getElementById("s" + this.obj + this.selectedNode); eOld.className = "node"; } eNew = document.getElementById("s" + this.obj + id); eNew.className = "nodeSel"; this.selectedNode = id; if (this.config.useCookies) this.setCookie('cs' + this.obj, cn.id); } }; // Toggle Open or close dTree.prototype.o = function(id) { var cn = this.aNodes[id]; this.nodeStatus(!cn._io, id, cn._ls); cn._io = !cn._io; if (this.config.closeSameLevel) this.closeLevel(cn); if (this.config.useCookies) this.updateCookie(); //更新选中值if(this.config.objValueId!='') this.update(); }; // Open or close all nodes dTree.prototype.oAll = function(status) { for (var n=0; n<this.aNodes.length; n++) { if (this.aNodes[n]._hc && this.aNodes[n].pid != this.root.id) { this.nodeStatus(status, n, this.aNodes[n]._ls) this.aNodes[n]._io = status; } } if (this.config.useCookies) this.updateCookie(); }; // Opens the tree to a specific node dTree.prototype.openTo = function(nId, bSelect, bFirst) { if (!bFirst) { for (var n=0; n<this.aNodes.length; n++) { if (this.aNodes[n].id == nId) { nId=n; break; } } } var cn=this.aNodes[nId]; if (cn.pid==this.root.id || !cn._p) return; cn._io = true; cn._is = bSelect; if (this.completed && cn._hc) this.nodeStatus(true, cn._ai, cn._ls); if (this.completed && bSelect) this.s(cn._ai); else if (bSelect) this._sn=cn._ai; this.openTo(cn._p._ai, false, true); }; // Closes all nodes on the same level as certain node dTree.prototype.closeLevel = function(node) { for (var n=0; n<this.aNodes.length; n++) { if (this.aNodes[n].pid == node.pid && this.aNodes[n].id != node.id && this.aNodes[n]._hc) { this.nodeStatus(false, n, this.aNodes[n]._ls); this.aNodes[n]._io = false; this.closeAllChildren(this.aNodes[n]); } } } // Closes all children of a node dTree.prototype.closeAllChildren = function(node) { for (var n=0; n<this.aNodes.length; n++) { if (this.aNodes[n].pid == node.id && this.aNodes[n]._hc) { if (this.aNodes[n]._io) this.nodeStatus(false, n, this.aNodes[n]._ls); this.aNodes[n]._io = false; this.closeAllChildren(this.aNodes[n]); } } } // Change the status of a node(open or closed) dTree.prototype.nodeStatus = function(status, id, bottom) { try{ eDiv = document.getElementById('d' + this.obj + id); eJoin = document.getElementById('j' + this.obj + id); //****选择 if(this.config.checkbox){ cbx = document.getElementById('cbx_' + this.obj + id); cbx.checked=status; cbxChild= eDiv.getElementsByTagName('input'); for(var i=0 ;i<cbxChild.length;i++){ cbxChild[i].checked=status; } } //****选择 if (this.config.useIcons) { eIcon = document.getElementById('i' + this.obj + id); eIcon.src = (status) ? this.aNodes[id].iconOpen : this.aNodes[id].icon; } eJoin.src = (this.config.useLines)? ((status)?((bottom)?this.icon.minusBottom:this.icon.minus):((bottom)?this.icon.plusBottom:this.icon.plus)): ((status)?this.icon.nlMinus:this.icon.nlPlus); eDiv.style.display = (status) ? 'block': 'none'; }catch(ex){ } }; // [Cookie] Clears a cookie dTree.prototype.clearCookie = function() { var now = new Date(); var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24); this.setCookie('co'+this.obj, 'cookieValue', yesterday); this.setCookie('cs'+this.obj, 'cookieValue', yesterday); }; // [Cookie] Sets value in a cookie dTree.prototype.setCookie = function(cookieName, cookieValue, expires, path, domain, secure) { document.cookie = escape(cookieName) + '=' + escape(cookieValue) + (expires ? '; expires=' + expires.toGMTString() : '') + (path ? '; path=' + path : '') + (domain ? '; domain=' + domain : '') + (secure ? '; secure' : ''); }; // [Cookie] Gets a value from a cookie dTree.prototype.getCookie = function(cookieName) { var cookieValue = ''; var posName = document.cookie.indexOf(escape(cookieName) + '='); if (posName != -1) { var posValue = posName + (escape(cookieName) + '=').length; var endPos = document.cookie.indexOf(';', posValue); if (endPos != -1) cookieValue = unescape(document.cookie.substring(posValue, endPos)); else cookieValue = unescape(document.cookie.substring(posValue)); } return (cookieValue); }; // [Cookie] Returns ids of open nodes as a string dTree.prototype.updateCookie = function() { var str = ''; for (var n=0; n<this.aNodes.length; n++) { if (this.aNodes[n]._io && this.aNodes[n].pid != this.root.id) { if (str) str += '.'; str += this.aNodes[n].value; } } this.setCookie('co' + this.obj, str); }; // [Cookie] Checks if a node id is in a cookie dTree.prototype.isOpen = function(id) { var aOpen = this.getCookie('co' + this.obj).split('.'); for (var n=0; n<aOpen.length; n++) if (aOpen[n] == id) return true; return false; }; // If Push and pop is not implemented by the browser if (!Array.prototype.push) { Array.prototype.push = function array_push() { for(var i=0;i<arguments.length;i++) this[this.length]=arguments[i]; return this.length; } }; if (!Array.prototype.pop) { Array.prototype.pop = function array_pop() { lastElement = this[this.length-1]; this.length = Math.max(this.length-1,0); return lastElement; } };
大家可以借鉴一下,自己弄个小工程试试,dtree还是不错的。