


Several forms of tree structure menus in JavaScript_javascript skills
This tree structure implements a function similar to breadcrumb navigation. It listens to the mouse movement event of the node, and then displays the child nodes below or to the right of the node, and so on. Recursively displays the child nodes of child nodes.
User homepage blog settings article album message comment system
There are a few small issues to pay attention to here. Firstly, this kind of tree structure is the absolute positioning of the suspended layer. When creating the layer, it must be placed directly on the body. Below, this is done to ensure that any layer can be covered in IE, because there are hidden rules for things like stacking context in IE. In addition, of course there is a select Can you cover me? An old question, here is to add an iframe element behind each floating layer. Of course, the menu at the same level only generates one iframe element. If the menu has several levels, it will generate several iframe masks. Then when the menu is displayed and hidden, it will be displayed and hidden at the same time. Hide iframe.
However, this kind of menu is not suitable for the front-end, because currently it only supports dynamically adding menu nodes in scripts, and cannot obtain menu nodes from existing html elements. For the sake of SEO and other front-end navigation, we usually dynamically add them in the background For output, if the menu has multiple levels, it is recommended not to exceed 2 levels. Customers will be too lazy to look at too many levels, but it is still very good to have a breadcrumb navigation display.
menu.js
/*
** Author : Jonllen
** Create : 2009-12-13
** Update : 2010-05-08
** SVN : 152
** WebSite: http://www.jonllen.com/
*/
var Menu = function (container) {
this.container = container;
return this;
}
Menu.prototype = {
list : new Array(),
active : new Array(),
iframes : new Array(),
settings : {
id : null,
parentId : 0,
name : null,
url : null,
level : 1,
parent : null,
children : null,
css : null,
element : null
},
push : function (item) {
var list = Object.prototype.toString.apply(item) === '[object Array]' ? item : [item];
for( var i=0; i< list.length; i ) {
var settings = list[i];
for( p in this.settings) {
if( !settings.hasOwnProperty(p) ) settings[p] = this.settings[p];
}
this.list.push(settings);
}
return this;
},
getChlid : function (id) {
var list = new Array();
for( var i=0;i < this.list.length; i )
{
var item = this.list[i];
if( item.parentId == id)
{
list.push(item);
}
}
return list;
},
render : function (container) {
var _this = this;
var menuElem = container || this.container;
for( var i=0;i < this.list.length; i )
{
var item = this.list[i];
if ( item.parentId != 0 ) continue;
var itemElem = document.createElement('div');
itemElem.innerHTML = '' item.name '';
itemElem.className = 'item';
if ( item.css ) itemElem.className = ' ' item.css;
var disabled = (' ' item.css ' ').indexOf(' disabled ')!=-1;
if ( disabled ) {
itemElem.childNodes[0].disabled = true;
itemElem.childNodes[0].className = 'disabled';
itemElem.childNodes[0].removeAttribute('href');
}
if ( (' ' item.css ' ').indexOf(' hidden ')!=-1 ) {
itemElem.style.display = 'none';
}
itemElem.menu = item;
itemElem.menu.children = this.getChlid(item.id);
itemElem.onmouseover = function (e){
_this.renderChlid(this);
};
menuElem.appendChild(itemElem);
}
document.onclick = function (e){
e = window.event || e;
var target = e.target || e.srcElement;
if (!target.menu) {
var self = _this;
for( var i=1;i<_this.active.length;i ) {
var item = _this.active[i];
var menuElem = document.getElementById('menu' item.id);
if ( menuElem !=null)
menuElem.style.display = 'none';
}
for(var j=1;j<_this.iframes.length;j ){
_this.iframes[j].style.display = 'none';
}
}
};
},
renderChlid : function (target){
var self = this;
var item = target.menu;
var activeItem = self.active[item.level];
while(activeItem) {
var activeItemElem = activeItem.element;
if ( activeItemElem!= null ) activeItemElem.style.display = 'none';
activeItem = self.active[activeItem.level 1];
}
self.active[item.level] = item;
var level = item.level;
while(this.iframes[level]) {
this.iframes[level].style.display = 'none';
level ;
}
var childElem = document.getElementById('menu' item.id);
if (childElem==null) {
var hasChild = false;
for( var j=0;j
hasChild = true;
break;
}
}
if( hasChild) {
var xy = self.elemOffset(target);
var x = xy.x;
var y = target.offsetHeight xy.y;
if ( item.level >= 2 )
{
x = target.offsetWidth - 1;
y -= target.offsetHeight;
}
childElem = document.createElement('div');
childElem.id = 'menu' item.id;
childElem.className = 'child';
childElem.style.position = 'absolute';
childElem.style.left = x 'px';
childElem.style.top = y 'px';
childElem.style.zIndex = 1000 item.level;
for( var i=0;i < item.children.length; i )
{
var childItem = item.children[i];
var childItemElem = document.createElement('a');
var disabled = (' ' childItem.css ' ').indexOf('disabled')!=-1;
if ( disabled ) {
childItemElem.disabled = true;
childItemElem.className = ' ' childItem.css;
}else {
childItemElem.href = childItem.url;
}
if ( (' ' childItem.css ' ').indexOf(' hidden ')!=-1 ) {
childItemElem.style.display = 'none';
}
childItemElem.innerHTML = childItem.name;
childItemElem.menu = childItem;
childItemElem.menu.children = self.getChlid(childItem.id);
var hasChild = false;
for( var j=0;j
hasChild = true;
break;
}
}
if( hasChild ) {
childItemElem.className = ' hasChild';
}
childItemElem.onmouseover = function (e) {
self.renderChlid(this)
};
childElem.appendChild(childItemElem);
}
document.body.insertBefore(childElem,document.body.childNodes[0]);
item.element = childElem;
}
}
if( childElem!=null) {
var iframeElem = this.iframes[item.level];
if ( iframeElem == null) {
iframeElem = document.createElement('iframe');
iframeElem.scrolling = 'no';
iframeElem.frameBorder = 0;
iframeElem.style.cssText = 'position:absolute; overflow:hidden;';
document.body.insertBefore(iframeElem,document.body.childNodes[0]);
this.iframes[item.level]=iframeElem;
}
childElem.style.display = 'block';
iframeElem.width = childElem.offsetWidth;
iframeElem.height = childElem.offsetHeight;
iframeElem.style.left = parseInt(childElem.style.left) 'px';
iframeElem.style.top = parseInt(childElem.style.top) 'px';
iframeElem.style.display = 'block';
}
},
elemOffset : function(elem){
if( elem==null) return {x:0,y:0};
var t = elem.offsetTop;
var l = elem.offsetLeft;
while( elem = elem.offsetParent) {
t = elem.offsetTop;
l = elem.offsetLeft;
}
return {x : l,y : t};
}
};
演示地址 http://demo.jb51.net/js/tree_json/menu.htm
打包下载地址
2.右键菜单树(ContextMenu)
自定义右键菜单(ContextMenu)和悬浮层树(Tree)其实现上都大同小异,都是在脚本里动态添加节点,然后在生成一个绝对定位层,只不过右键菜单树(ContextMenu)触发的事件不一样。另外右键菜单还需要提供一个动态添加菜单项功能,以实现右击不同的元素可以显示不同的右键菜单,我这里提供一种"回调函数",使用见如下代码:
ContextMenu回调函数
//ContextMenu
var contextmenu = new ContextMenu(...{ container : document.getElementById('treemenu') });
contextmenu.push( ...{ html : 'Powered By: Jonllen', css : 'disabled'});
contextmenu.push( ...{ html : '', css : 'line'});
contextmenu.push( ...{ html : '刷新(R)', href : 'javascript:location.reload();'});
for(var i=0;i
id : menu[i].id,
level : menu[i].level,
parentId : menu[i].parentId,
html : menu[i].name,
href : menu[i].url
});
}
contextmenu.render();
//原有回调函数
var contextmenuOnShow = contextmenu.onShow;
//设置新的回调函数
contextmenu.onShow = function (target, _this)...{
var item = target.treemenu || target.parentNode.treemenu;
if( item ) ...{
var html = '添加' item.html '“子节点' (item.children.length 1) '”';
_this.push( ...{
html : html,
click : function (e)...{
item.expand = false;
var newItem = ...{
id : item.id '0' (item.children.length 1),
level : item.level 1,
parentId : item.id,
html : item.html '子节点' (item.children.length 1),
href : '#',
css : 'item',
createExpand : true
};
item.children.push(newItem);
treemenu.list.push(newItem);
treemenu.renderChild(item);
},
clickClose : true,
index : 1,
type : 'dynamic'
});
_this.push( ...{
html : '删除节点“' item.html '”',
click : function (e)...{
if( confirm('是否确认删除节点“' item.html '”?'))
treemenu.remove(item);
},
clickClose : true,
index : 2,
type : 'dynamic'
});
}
contextmenuOnShow(target, _this);
};
So how to implement the "callback function"? In fact, it is very simple. When the function reaches a certain line of code, it runs a preset "callback function". It is a bit like an event mechanism, like binding multiple window.onload events. Since there may be bound functions before, record the previous functions first. , then set the newly bound function, and then call the previously bound function. The code shown above realizes that if the right-click element is a treemenu node, the add and delete treemenu node menu will be added in the right-click. The effect is shown in the node tree (TreeMenu) example below.
We need to pay attention to the scope in the callback function. The this pointer points to the current callback function object, not the context in which the callback function is run. However, we can also use the call method to run the callback function in the current this context. Here I adopt the method of passing 2 parameters to the callback function, so that the callback function can easily obtain this object and other variables. This is commonly used in the Ajax Callback function.
The custom right-click menu (ContextMenu) is only suitable for shortcut operations of some auxiliary functions. For example, if there are some OA systems with complex business functions, I will also use it in conjunction with the node tree (TreeMenu) below. If possible, try not to use the right-click menu. Firstly, users need to be trained in the habit of right-clicking. Secondly, customizing the right-click menu loses some functions of the original right-click menu, such as viewing source files.
Here is the right-click menu area.
Right-click me and you can see the properties.
You can also select me and right-click to copy.
Can you cover me?
ContextMenu.js
/**//*
** Author : Jonllen
** Create : 2010-05-01
** Update : 2010-05-09
** SVN : 153
** WebSite: http://www.jonllen.com/
*/
var ContextMenu = function (settings) ...{
for( p in this.settings)
...{
if( !settings.hasOwnProperty(p) ) settings[p] = this.settings[p];
}
this.settings = settings;
this.settings.menu = document.createElement('div');
this.settings.menu.className = this.settings.css;
this.settings.menu.style.cssText = 'position:absolute;display:none;';
document.body.insertBefore(this.settings.menu,document.body.childNodes[0]);
return this;
}
ContextMenu.prototype = ...{
list : new Array(),
active : new Array(),
iframes : new Array(),
settings : ...{
menu : null,
excursionX : 0,
excursionY : 0,
css : 'contextmenu',
container : null,
locked : false
},
item : ...{
id : null,
level : 1,
parentId : 0,
html : '',
title : '',
href : 'javascript:;',
target : '_self',
css : null,
element : null,
childElement : null,
parent : null,
children : null,
type : 'static',
click : null,
clickClose : false
},
push : function (item) ...{
var list = Object.prototype.toString.apply(item) === '[object Array]' ? item : [item];
for( var i=0; i< list.length; i ) ...{
var _item = list[i];
for( p in this.item) ...{
if( !_item.hasOwnProperty(p) ) _item[p] = this.item[p];
}
_item.element = null;
if( _item.name ) _item.html = _item.name;
if( _item.url ) _item.href = _item.url;
if( _item.type == 'static') ...{
this.list.push(_item);
}else ...{
if(this.dynamic == null) this.dynamic = new Array();
this.dynamic.push(_item);
}
}
return this;
},
bind : function ()...{
var _this = this;
for( var i=0; this.dynamic && i
var item = this.dynamic[i];
var itemElem = document.createElement('div');
itemElem.title = item.title;
itemElem.innerHTML = '' item.html '';
itemElem.className = 'item ' (item.css?' ' item.css:'');
item.element = itemElem;
if( item.click ) ...{
(function (item)...{
item.element.childNodes[0].onclick = function (e)...{
if( item.clickClose) _this.hidden();
return item.click(e);
};
})(item);
}
itemElem.contextmenu = item;
itemElem.onmouseover = function (e)...{ _this.hidden(item.level);};
var index = item.index || 0;
if( index >= this.settings.menu.childNodes.length)
index = this.settings.menu.childNodes.length - 1;
if( index < 0 )
this.settings.menu.appendChild(itemElem);
else
this.settings.menu.insertBefore(itemElem, this.settings.menu.childNodes[index]);
}
},
render : function ( container ) ...{
var _this = this;
container = container || this.settings.container;
this.settings.menu.innerHTML = '';
for( var i=0;i < this.list.length; i )
...{
var item = this.list[i];
if ( item.parentId != 0 ) continue;
var itemElem = document.createElement('div');
itemElem.title = item.title;
itemElem.innerHTML = '' item.html '';
itemElem.className = 'item ' (item.css?' ' item.css:'');
var disabled = _this.hasClass(itemElem, 'disabled');
if ( disabled ) ...{
itemElem.childNodes[0].disabled = true;
itemElem.childNodes[0].className = 'disabled';
itemElem.childNodes[0].removeAttribute('href');
}
if ( _this.hasClass(itemElem, 'hidden') ) ...{
itemElem.style.display = 'none';
}
if( item.click ) ...{
(function (item)...{
item.element.childNodes[0].onclick = function (e)...{
if( item.clickClose) _this.hidden();
return item.click(e);
};
})(item);
}
itemElem.contextmenu = item;
itemElem.contextmenu.children = this.getChlid(item.id);
if( itemElem.contextmenu.children.length > 0 )
itemElem.childNodes[0].className = ' hasChild';
itemElem.onmouseover = function (e)...{ _this.renderChlid(this);};
this.settings.menu.appendChild(itemElem);
}
this.active[0] = ...{ element : _this.settings.menu };
this.settings.menu.contextmenu = _this;
container.oncontextmenu = function (e)...{
e = window.event || e;
var target = e.target || e.srcElement;
if( e.preventDefault)
e.preventDefault();
var mouseCoords = _this.mouseCoords(e);
_this.settings.menu.style.left = mouseCoords.x _this.settings.excursionX 'px';
_this.settings.menu.style.top = mouseCoords.y _this.settings.excursionY 'px';
_this.hidden();
_this.show(0, target);
return false;
};
this.addEvent(document, 'click', function (e)...{
e = window.event || e;
var target = e.target || e.srcElement;
var isContextMenu = !!target.contextmenu;
if( isContextMenu == false) ...{
var parent = target.parentNode;
while( parent!=null) ...{
if( parent.contextmenu) ...{
isContextMenu = true;
break;
}
parent = parent.parentNode;
}
}
if (isContextMenu == false) ...{
_this.hidden();
}
});
},
renderChlid : function ( target )...{
if(this.settings.locked) return;
var contextmenu = target.contextmenu;
var currentLevel = contextmenu.level;
this.hidden(currentLevel);
var hasChild = false;
for( var j=0;j
hasChild = true;
break;
}
}
if( !hasChild) return;
var childElem = contextmenu.element;
if (childElem == null) ...{
childElem = document.createElement('div');
childElem.className = this.settings.css;
childElem.style.position = 'absolute';
childElem.style.zIndex = 1000 contextmenu.level;
var _this = this;
for( var i=0;i < contextmenu.children.length; i )
...{
var childItem = contextmenu.children[i];
var childItemElem = document.createElement('div');
childItemElem.title = childItem.title;
childItemElem.innerHTML = '' childItem.html '';
childItemElem.className = 'item' (childItem.css?' ' childItem.css : '');
var disabled = this.hasClass(childItemElem, 'disabled');
if ( disabled ) ...{
childItemElem.childNodes[0].disabled = true;
childItemElem.childNodes[0].removeAttribute('href');
}
if ( this.hasClass(childItemElem, 'hidden') ) ...{
childItemElem.style.display = 'none';
}
if( childItem.click ) ...{
(function (childItem)...{
childItem.element.childNodes[0].onclick = function (e)...{
if( childItem.clickClose) _this.hidden();
return childItem.click(e);
};
})(childItem);
}
childItem.parent = contextmenu;
childItemElem.contextmenu = childItem;
childItemElem.contextmenu.children = this.getChlid(childItem.id);
var hasChild = false;
for( var j=0; j
hasChild = true;
break;
}
}
if( hasChild ) ...{
childItemElem.childNodes[0].className = ' hasChild';
}
childItemElem.onmouseover = function (e)...{ _this.renderChlid(this);};
childElem.appendChild(childItemElem);
}
document.body.insertBefore(childElem,document.body.childNodes[0]);
contextmenu.element = childElem;
}
this.active[currentLevel] = contextmenu;
var xy = this.elemOffset(target);
var x = xy.x target.offsetWidth this.settings.excursionX;
var y = xy.y this.settings.excursionY;
childElem.style.left = x 'px';
childElem.style.top = y 'px';
childElem.style.display = 'block';
this.show(currentLevel);
},
getChlid : function (id) ...{
var list = new Array();
for( var i=0;i < this.list.length; i )
...{
var item = this.list[i];
if( item.parentId == id)
...{
list.push(item);
}
}
return list;
},
show : function (level, target) ...{
if(this.settings.locked) return;
level = level || 0;
var item = this.active[level];
if ( level == 0 ) ...{
for( var i=0;this.dynamic && i < this.dynamic.length; i )
...{
var dynamicItemElem = this.dynamic[i].element;
if( dynamicItemElem !=null) dynamicItemElem.parentNode.removeChild(dynamicItemElem);
}
if (this.dynamic) this.dynamic.length = 0;
this.onShow(target, this);
}
var menuElem = item.element;
menuElem.style.display = 'block';
var iframeElem = this.iframes[level];
if ( iframeElem == null) ...{
iframeElem = document.createElement('iframe');
iframeElem.scrolling = 'no';
iframeElem.frameBorder = 0;
iframeElem.style.cssText = 'position:absolute; overflow:hidden;';
document.body.insertBefore(iframeElem,document.body.childNodes[0]);
this.iframes.push(iframeElem);
}
iframeElem.width = menuElem.offsetWidth;
iframeElem.height = menuElem.offsetHeight;
var menuElemOffset = this.elemOffset(menuElem);
iframeElem.style.left = menuElemOffset.x 'px';
iframeElem.style.top = menuElemOffset.y 'px';
iframeElem.style.display = 'block';
},
onShow : function (target, _this) ...{
if( target.nodeType == 1 && target.tagName == 'A' && target.innerHTML.indexOf('.rar') != -1 )...{
//解压文件
_this.push( ...{
html : '解压缩到“' target.innerHTML.substring(0,target.innerHTML.lastIndexOf('.')) '\”...',
click : function (e)...{
e = e || window.event;
var srcElement = e.srcElement || e.target;
srcElement.className = 'on';
srcElement.innerHTML = '解压缩到“' target.innerHTML.substring(0,target.innerHTML.lastIndexOf('.')) '\”...';
var url = '/Ajax/FileZip.aspx?mode=unzip&files=' target.href.substring(target.href.replace('//','xx').indexOf('/'));
if( typeof Ajax == 'undefined') return;
Ajax.get(url, function (data, _this)...{
_this.settings.locked = true;
eval(data);
if( rs.success ) ...{
location.reload();
}else...{
alert(rs.error);
_this.hidden();
}
}, _this);
srcElement.onclick = null;
_this.settings.locked = true;
},
clickClose : false,
index : 2,
type : 'dynamic'
});
}
else if( target.nodeType == 1 && target.title.indexOf('添加到') == 0) ...{
//添加单个压缩文件
_this.push( ...{
html : target.title,
title : target.title,
click : function (e)...{
var index = target.href.indexOf('?path=');
if( index != -1)...{
var fullName = target.href.substring(index '?path='.length);
}else ...{
var fullName = target.href.substring(target.href.replace('//','xx').indexOf('/'));
}
e = e || window.event;
var srcElement = e.srcElement || e.target;
srcElement.className = 'on';
srcElement.innerHTML = '正在添加到“' fullName.substring(fullName.lastIndexOf('/') 1) '.rar”...';
var url = '/Ajax/FileZip.aspx?mode=zip&files=' fullName;
if( typeof Ajax == 'undefined') return;
Ajax.get(url, function (data, _this)...{
_this.settings.locked = true;
eval(data);
if( rs.success ) ...{
location.reload();
}else...{
alert(rs.error);
_this.hidden();
}
}, _this);
srcElement.onclick = null;
_this.settings.locked = true;
},
clickClose : false,
index : 2,
type : 'dynamic',
css : 'on'
});
}else ...{
//添加多个压缩文件
var fileName = '';
var files = new Array();
var ids = document.getElementsByName('ids');
for( var i=0; i
var file = ids[i].value;
files.push(file);
if( files.length == 1) ...{
fileName = file.substring(file.lastIndexOf('/') 1) '.rar';
}
}
if( files.length > 0 )...{
_this.push( ...{
html : '添加' files.length '个文件到压缩包“' fileName '”',
click : function (e)...{
e = e || window.event;
var srcElement = e.srcElement || e.target;
srcElement.className = 'on';
srcElement.innerHTML = '正在添加到“' fileName '”...';
var url = '/Ajax/FileZip.aspx?mode=zip&files=' files.join('|');
if( typeof Ajax == 'undefined') return;
Ajax.get(url, function (data, _this)...{
_this.settings.locked = true;
eval(data);
if( rs.success ) ...{
location.reload();
}else...{
alert(rs.error);
_this.hidden();
}
}, _this);
srcElement.onclick = null;
_this.settings.locked = true;
},
clickClose : false,
index : 2,
type : 'dynamic'
});
}
}
if( target.nodeType == 1 && target.tagName == 'A') ...{
_this.push( ...{
html : '属性“' target.innerHTML '”',
href : target.href,
click : function (e)...{
prompt('属性“' target.innerHTML '”',target.href);
return false;
},
clickClose : true,
index : 3,
type : 'dynamic'
});
}
var selection = window.getSelection ? window.getSelection().toString() : document.selection.createRange().text;
if( selection ) ...{
_this.push( ...{
html : '复制“' (selection.length > 15 ? selection.substring(0,12) '...' : selection) '”',
title : '复制“' selection '”',
click : function (e) ...{
if(window.clipboardData) ...{
window.clipboardData.clearData();
window.clipboardData.setData("Text", selection);
}else ...{
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var clip = Components.classes['@mozilla.org/widget/clipboard;1'].createInstance(Components.interfaces.nsIClipboard);
var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable);
if (!clip || !trans) return;
trans.addDataFlavor('text/unicode');
var len = new Object();
var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
str.data = selection;
trans.setTransferData("text/unicode",str,selection.length*2);
var clipid=Components.interfaces.nsIClipboard;
if (!clip) return false;
clip.setData(trans,null,clipid.kGlobalClipboard);
}
},
clickClose : true,
index : 0,
type : 'dynamic'
});
}
_this.bind();
},
hidden : function (level) ...{
level = level || 0;
for( var i = level; i
var iframeElem = this.iframes[i];
if ( iframeElem !=null)
iframeElem.style.display = 'none';
if(this.settings.locked) return;
var menuElem = item.element;
if ( menuElem !=null)
menuElem.style.display = 'none';
}
this.onHidden(level);
},
onHidden : function (level) ...{
},
hasClass : function (elem, name)
...{
return !!elem && (' ' elem.className ' ').indexOf(' ' name ' ') != -1;
},
elemOffset : function(elem)...{
var left = 0;
var top = 0;
while (elem.offsetParent)...{
left = elem.offsetLeft;
top = elem.offsetTop;
elem = elem.offsetParent;
}
left = elem.offsetLeft;
top = elem.offsetTop;
return ...{x:left, y:top};
},
mouseCoords : function (e)...{
if (e.pageX && e.pageY) ...{
return ...{
x: e.pageX,
y: e.pageY
};
}
var d = (document.documentElement && document.documentElement.scrollTop) ? document.documentElement : document.body;
return ...{
x: e.clientX d.scrollLeft,
y: e.clientY d.scrollTop
};
},
addEvent : function(target,eventType,func)...{
if(target.attachEvent)
...{
target.attachEvent("on" eventType, func);
}else if(target.addEventListener)
...{
target.addEventListener(eventType == 'mousewheel' ? 'DOMMouseScroll' : eventType, func, false);
}
return this;
},
removeEvent : function(target,eventType,func)...{
if(target.detachEvent)
...{
target.detachEvent("on" eventType, func);
}else if(target.removeEventListener)
...{
target.removeEventListener(eventType == 'mousewheel' ? 'DOMMouseScroll' : eventType, func, false);
}
return this;
}
}
Demo addresshttp://demo.jb51.net/js/tree_json/ContextMenu.htm
3. Node Tree (TreeMenu)
Node tree (TreeMenu) is the most used in our actual projects. The famous MzTreeVew of Meihuaxue on the Internet has been optimized for large amounts of data and is very efficient. But I don’t really like to adopt things. Since I don’t understand some things or why they do what they do, I want to try to “invent the wheel” myself. Of course, the function is definitely not as powerful as MzTreeVew. I did not do an efficiency test when the amount of data was large. I borrowed the pictures from MzTreeVew first.
Infinite-level node tree
To achieve infinite-level functions, if there are no tricks, it seems that the only way is recursion. However, it should be noted that there must be a correct condition to determine the return to avoid an infinite loop. In terms of data storage structure, generally our database stores id, name, and parentId fields. This structure is still stored in the tree structure. When expanding a tree node, we need to obtain all its child nodes based on the id and save them. , to avoid repeated traversal for the second time.
Hierarchical relationship structure
What I want to say here is that the HTML presented has a hierarchical relationship, and each tree node object has a hierarchical relationship. The HTML hierarchical relationship shows that the elements of the child nodes must be the child nodes of the elements of the parent node. Originally I thought this was not necessary. Later I found that only by doing this can the state of the child nodes be maintained. For example, if I click on a first-level node, I only need Expand all second-level nodes, and the status of third-level or fourth-level nodes does not need to be changed. The HTML structure is easy to implement with this hierarchical relationship support. Corresponding to this is the tree node object, which stores parent node objects, child node collection objects, reference elements, etc. to facilitate recursive calls. This information is attached to the corresponding DOM element.
With checkbox and radio selection
The needs of actual projects are complex and changeable. Sometimes we need to provide radio single selection function, and sometimes we may need to provide checkbox multi-selection function. In order to It is also necessary to directly obtain the selected value in the background and provide checkbox and radio selection functions. Of course, we can configure and specify whether to create a checkbox or radio during instantiation. Whether each node is selected during initialization can also be set and specified. What needs to be noted here is that we cannot specify the name attribute when we directly create a checkbox or radio. In a twist, Just think of it to achieve it.
var inputTemp = document.createElement('div');
inputTemp.innerHTML = '';
var inputElem = inputTemp.childNodes[0];
Tie only Define a click event
It looks like a more complicated tree structure, but in fact I only bound a click event to the outermost container element. In addition, the linkage of clicking the checkbox is also handled in this click event, because The element's event will bubble up and trigger to the parent element, and it is easy to use the event object event to get the trigger source element, so I can get whether you clicked on the checkbox or some other element, which is very convenient. The advantage of this is that you can focus on processing one event instead of adding events to each element, which fully demonstrates the elegance and beauty of the code.
Demo effect: http://demo.jb51.net/js/tree_json/TreeMenu.htm
Package download addressJavaScript multiple tree structure menu effects
Reprinted in this article From Jinlong Blog: http://www.jonllen.com/jonllen/js/menu.aspx, please keep this statement when reprinting.

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



How to use WebSocket and JavaScript to implement an online speech recognition system Introduction: With the continuous development of technology, speech recognition technology has become an important part of the field of artificial intelligence. The online speech recognition system based on WebSocket and JavaScript has the characteristics of low latency, real-time and cross-platform, and has become a widely used solution. This article will introduce how to use WebSocket and JavaScript to implement an online speech recognition system.

WebSocket and JavaScript: Key technologies for realizing real-time monitoring systems Introduction: With the rapid development of Internet technology, real-time monitoring systems have been widely used in various fields. One of the key technologies to achieve real-time monitoring is the combination of WebSocket and JavaScript. This article will introduce the application of WebSocket and JavaScript in real-time monitoring systems, give code examples, and explain their implementation principles in detail. 1. WebSocket technology

Introduction to how to use JavaScript and WebSocket to implement a real-time online ordering system: With the popularity of the Internet and the advancement of technology, more and more restaurants have begun to provide online ordering services. In order to implement a real-time online ordering system, we can use JavaScript and WebSocket technology. WebSocket is a full-duplex communication protocol based on the TCP protocol, which can realize real-time two-way communication between the client and the server. In the real-time online ordering system, when the user selects dishes and places an order

How to use WebSocket and JavaScript to implement an online reservation system. In today's digital era, more and more businesses and services need to provide online reservation functions. It is crucial to implement an efficient and real-time online reservation system. This article will introduce how to use WebSocket and JavaScript to implement an online reservation system, and provide specific code examples. 1. What is WebSocket? WebSocket is a full-duplex method on a single TCP connection.

JavaScript and WebSocket: Building an efficient real-time weather forecast system Introduction: Today, the accuracy of weather forecasts is of great significance to daily life and decision-making. As technology develops, we can provide more accurate and reliable weather forecasts by obtaining weather data in real time. In this article, we will learn how to use JavaScript and WebSocket technology to build an efficient real-time weather forecast system. This article will demonstrate the implementation process through specific code examples. We

JavaScript tutorial: How to get HTTP status code, specific code examples are required. Preface: In web development, data interaction with the server is often involved. When communicating with the server, we often need to obtain the returned HTTP status code to determine whether the operation is successful, and perform corresponding processing based on different status codes. This article will teach you how to use JavaScript to obtain HTTP status codes and provide some practical code examples. Using XMLHttpRequest

Usage: In JavaScript, the insertBefore() method is used to insert a new node in the DOM tree. This method requires two parameters: the new node to be inserted and the reference node (that is, the node where the new node will be inserted).

The native Messages app on iPhone lets you easily edit sent texts. This way, you can correct your mistakes, punctuation, and even autocorrect wrong phrases/words that may have been applied to your text. In this article, we will learn how to edit messages on iPhone. How to Edit Messages on iPhone Required: iPhone running iOS16 or later. You can only edit iMessage text on the Messages app, and then only within 15 minutes of sending the original text. Non-iMessage text is not supported, so they cannot be retrieved or edited. Launch the Messages app on your iPhone. In Messages, select the conversation from which you want to edit the message
