CodeWeblog.com » lt,amp,principle » javascript html js many custom class linkage floating menu, js produced menu

javascript html js many custom class linkage floating menu, js produced menu

Procedures for Principle (recommended reading by reference to the code):

Procedures are based on traditional floating menu to expand from here, let me talk about some more crucial or useful places:

【Function】 Delay
A lot of people understand this is to set up a setTimeout timer, there are two timer, are separately containers timer timer and menu.
Timer is the role of containers move the mouse outside the container when the hidden containers, are difficult to judge how the current mouse are not in the container outside.
General approach is to set up a bool parameter, mouseout, when set to false, mouseover, when set to true (or the other way around), and then judge based on this parameter,
However, this method will not work in this, after the menu container object will trigger container mouseout,
Case because of bubbling, the menu object will trigger the mouseout container mouseout.
For example:

<div>
<div>
</div>
</div>


Recommend a method here, using the contains (ff are compareDocumentPosition) method.
The method is to do my picture slide show effects of muxrwc taught me:

var isIn = false, oT = Event(e).relatedTarget;
Each(oThis.Container, function(o, i){ if(o.contains ? o.contains(oT) || o == oT : o.compareDocumentPosition(oT) & 16){ isIn = true; } });


Detailed reference content like lightbox effects, while the menu timer on nothing in particular, is used to set the menu content.

【Location】 floating
Apart from the mother container menu are fixed, and sub-menu of the container is absolutely positioning, positioning the key is fit to obtain the left and top value.
First of all, to get a menu on the left and top value.
Menu because of the mother is a relative positioning, it is necessary to check that it's absolute left and top value on the value must be up layer by layer, and add up to:

while (o.offsetParent) { o = o.offsetParent; iLeft += o.offsetLeft; iTop += o.offsetTop; }


Made up a menu of left and top value, then the corresponding displacement can be a:

switch (position.toLowerCase()) {
    case "up" :
        iTop -= oContainer.offsetHeight;
        break;
    case "down" :
        iTop += o.offsetHeight;
        break;
    case "left" :
        iLeft -= oContainer.offsetWidth;
        break;
    case "right" :
    default :
        iLeft += o.offsetWidth;
}
here to note that if none of the display as it would not be able to obtain offset values,
So in order to hide at the status can be targeted, it is necessary to use visibility to hide.
Of course, if the display can show the re-positioning, but it will appear the moment the situation of mobile, it is not recommended.

Automatic generation of container object 【】
Apart from the first container object, when found in containers not enough will, in accordance with the previous container to generate a new container.
I want to start using cloneNode, but because of the object in case there is so such use should not only build a manual.

First of all, before a container in accordance with the tagName to create a new container,
In order to use the same style, copy cssText (This is the muxrwc told me) and the className to the new containers,
And with IniContainer () function you can set the:

var oPre = this.Container[i-1], oNew = document.body.appendChild(document.createElement(oPre.tagName));
oNew.style.cssText = oPre.style.cssText; oNew.className = oPre.className;
this.IniContainer(this.Container[i] = oNew, true);


Linkage】 many class
Multi-level interaction, the key is how to get sub-menu structure and the basis of this sub-menu to generate the menu structure of the object.
First talk about the menu structure, are similar to this structure:

json know
[
    {'txt': '1' },
    {'txt': '2', 'position': 'down', 'menu': [
        {'txt': '2_1'},
        {'txt': '2_2'}
    ]}
]
should all know what are, js a target structure:
txt contents are displayed may also be a html, when it will be inserted into innerHTML;
position is the position, can be "right" (default), "down", "up", "left", the floating position to set the basis of this value;
menu are the next level of menu structure.
Can be seen similar to a n-dimensional array, are similar attention.

How it was in accordance with the menu structure of the current menu Submenu it?
First of all objects from the menu onmouseover begins,
At the onmouseover menu a Medium, to do is re-instated and re-set the menu style (this later).
Settings menu also includes the provision of an index property index to record the current menu container index (number of containers the first menu),
Here is rather tricky container index menu menu structure with the corresponding index in the menu are the same (the back will be used),
_index Containers and are the current index (the first of several containers), this same index can also be used to indicate the current menu at the first class a few.
_onmenu Would also like to set the menu for the current object, its location at the floating check needed.
And you can use Set () procedure to set up a menu:

oThis._timerMenu = setTimeout(function(){
    oContainer.index = i; oThis._onmenu = oMenu; oThis._index = index + 1;  oThis.Set();
}, oThis.Delay);
in Set () procedure is to first hide the first select, This is a common practice:

Each(document.getElementsByTagName("select"), function(o){ o.style.visibility = "hidden"; })


Setting a parameter, as the index of the collection containers, you can directly start from the second class, so i set the initial value of 1.
A while to repeatedly check sub-menu structure (menu), until there are no sub-menu (menu length is 0) or to obtain a sub-menu structure (_index == i).
There is no use for, because while I think the more appropriate, or perhaps for better.
Here, apart from sub-menu structure should be made to obtain sub-menu positioning (position).
If the container is not enough during the period will be automatically added.
Made sub-menu structure and positioning, you can use SetContainer () set up a container at a lower level menu:

var i = 1;
while (menu.length > 0) {
    //获取子菜单结构和定位
    
    //如果容器不够就根据前一个自动添加
    
    //设置下一级菜单
    if(this._index == i++){ this.SetContainer(menu, position); break; }
}

Procedures SetContainer () with few skills, the first set of containers associated with the use of SetMenu () to set the menu object,
And are the positioning and display containers, and finally Do not need to hide the containers, this part is not illustrated.

Want to talk about are the SetMenu () procedure, its role is to set the menu under the menu structure on the object and container.
According to the menu structure of each element to create a menu object, innerHTML elements txt property, set mouseover case, the last appendChild to the container.
More important here are mouseover events at mouseover case will be re-instated and re-set the menu style,
When the trigger mouseover on the case back to the beginning of one of the "object from the menu onmouseover about" (reincarnation !-_-)。
I do not know you do not halo halo, since the beginning of me is more of a halo.

【Focus style settings】
Say here is SetMenu () to re-set the style part.
Procedures can be seen in the mouse menu and specify the parent menu will use another definition of the style to display.
General practice is at mouseover and mouseout set style,
But not here, because there is delay, when the fast-moving mouse to another menu, and then moved to the original menu, the
Style does not automatically set up on the back, so had no choice but to re-set every time mouseover each container style menu.
Temporarily can not find a better way, so remember to inform me Oh o (_ _) o

Each(oThis.Container, function(o, i){
    if(i > index) return;
    Each(o.getElementsByTagName(oThis.Tag), function(o){ o.className = oThis.Class; });
    if(i == index){
        oMenu.className = oThis.onClass;
    } else if(o.index >= 0) {
        o.getElementsByTagName(oThis.Tag)[o.index].className = oThis.onClass;
    } else return;
});


】 【Extensions
Have these attributes can be set:
Position: The default location (up, down, left, right);
Tag: default tag generated;
Class: default style;
onClass: focus style;
Delay: delay value (ms);

The time being there is this two methods:
Add (menu): Add menu, parameters are a menu structure;
Delete (index): delete the menu, the menu parameters are indexed;

_menu Can also directly modify the property, how to expand your imagination on the look.

Procedures for testing:
Parameter 1 is a collection of containers:

var arrContainer=["idMenu1"]; 


Parameter 2 is a menu structure:

var menu = [
    {'txt': '1 <a href="http://shundebk.cn/">link</a>' },
    {'txt': '2 →', 'menu': [
        {'txt': '2_1'},
        {'txt': '2_2'}
    ]},
    {'txt': '3 →', 'menu': [
        {'txt': '3_1 ↑', 'position': 'up', 'menu': [
            {'txt': '3_1_1'},
            {'txt': '3_1_2'}
        ]},
        {'txt': '3_2'}
    ]},
    {'txt': '4 →', 'menu': [
        {'txt': '4_1 ↓', 'position': 'down', 'menu': [
            {'txt': '4_1_1 →', 'menu': [
                {'txt': '4_1_1_1'}
            ]}
        ]}
    ]},
    {'txt': '5 →', 'menu': [
        {'txt': '5_1 →', 'menu': [
            {'txt': '5_1_1 ↓', 'position': 'down', 'menu': [
                {'txt': '5_1_1_1 ←', 'position': 'left', 'menu': [
                    {'txt': '5_1_1_1_1'}
                ]}
            ]}
        ]}
    ]}
];

3 parameters are some settings:

{ Delay: 200, onClass: "on" }


Instantiated object:

new CascadeMenu(arrContainer, arrMenu, { Delay: 200, onClass: "on" });


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>JavaScript 自定义多级联动浮动菜单</title>
<script type="text/javascript">
var $ = function (id) {
	return "string" == typeof id ? document.getElementById(id) : id;
};

function addEventHandler(oTarget, sEventType, fnHandler) {
	if (oTarget.addEventListener) {
		oTarget.addEventListener(sEventType, fnHandler, false);
	} else if (oTarget.attachEvent) {
		oTarget.attachEvent("on" + sEventType, fnHandler);
	} else {
		oTarget["on" + sEventType] = fnHandler;
	}
};

function Event(e){
	var oEvent = document.all ? window.event : e;
	if (document.all) {
		if(oEvent.type == "mouseout") {
			oEvent.relatedTarget = oEvent.toElement;
		}else if(oEvent.type == "mouseover") {
			oEvent.relatedTarget = oEvent.fromElement;
		}
		
		oEvent.stopPropagation = function() { this.cancelBubble = true; }
	}
	return oEvent;
}

function Each(list, fun){
	for (var i = 0, len = list.length; i < len; i++) { fun(list[i], i); }
};


var Class = {
  create: function() {
	return function() {
	  this.initialize.apply(this, arguments);
	}
  }
}

Object.extend = function(destination, source) {
	for (var property in source) {
		destination[property] = source[property];
	}
	return destination;
}


var CascadeMenu = Class.create();
CascadeMenu.prototype = {
  //初始化对象(容器集合, 菜单结构)
  initialize: function(arrContainer, arrMenu, options) {
	if(arrContainer.length <= 0 || arrMenu.lenght <= 0) return;
	
	var oThis = this;
	
	this._timerContainer = null;//容器定时器
	this._timerMenu = null;//菜单定时器
	this._onmenu = null;//当前菜单对象
	this._index = -1;//要设置容器的索引
	
	this.Container = [];//容器集合
	this._menu = arrMenu;//菜单结构
	
	this.SetOptions(options);
	
	this.Position = this.options.Position || "right";
	this.Delay = parseInt(this.options.Delay) || 0;
	this.Class = this.options.Class || "";
	this.onClass = this.options.onClass || this.Class;
	this.Tag = this.options.Tag;
	
	//设置容器
	Each(arrContainer, function(o, i){ oThis.IniContainer(oThis.Container[i] = (o = $(o)), i > 0); });
	
	this.Ini();
  },
  //设置默认属性
  SetOptions: function(options) {
	this.options = {//默认值
		Position:	"right",//默认位置(up,down,left,right)
		Tag:		"div",//默认生成标签
		Class:		"",//默认样式
		onClass:	"",//焦点样式
		Delay:		0//延迟值(微秒)
	};
	Object.extend(this.options, options || {});
  },
  //初始化容器(容器集合, 是否子菜单容器)
  IniContainer: function(container, bChild) {
	var oThis = this;
	addEventHandler(container, "mouseover", function(){ clearTimeout(oThis._timerContainer); });
	addEventHandler(container, "mouseout", function(e){
		//是否在菜单之内
		var isIn = false, oT = Event(e).relatedTarget;
		Each(oThis.Container, function(o, i){ if(o.contains ? o.contains(oT) || o == oT : o.compareDocumentPosition(oT) & 16){ isIn = true; } });
		//在菜单外隐藏
		if(!isIn){
			clearTimeout(oThis._timerContainer); clearTimeout(oThis._timerMenu);
			oThis._timerContainer = setTimeout(function(){ oThis.Hide(); }, oThis.Delay);
		}
	});
	//重置索引
	container.index = -1;
	//子菜单容器设置
	if (bChild) { container.style.position = "absolute"; container.style.visibility = "hidden"; }
  },
  //初始化第一个容器
  Ini: function() {
	this.Container[0].innerHTML = ""; this._index = 0; this.SetMenu(this._menu);
  },
  //全局设置
  Set: function() {
	//隐藏select
	Each(document.getElementsByTagName("select"), function(o){ o.style.visibility = "hidden"; })
	
	var menu = this._menu;
	//第一个不需要处理所以从1开始
	var i = 1;
	while (menu.length > 0) {
		//获取子菜单结构和定位
		var iC = this.Container[i-1].index, position = this.Position;
		if(iC >= 0){
			//这里要先取position再设menu
			position = menu[iC].position || this.Position; menu = menu[iC].menu || [];
		} else { menu = []; }
		
		//如果容器不够就根据前一个自动添加
		if(!this.Container[i]){
			var oPre = this.Container[i-1], oNew = document.body.appendChild(document.createElement(oPre.tagName));
			oNew.style.cssText = oPre.style.cssText; oNew.className = oPre.className;
			this.IniContainer(this.Container[i] = oNew, true);
		}
		
		//设置下一级菜单
		if(this._index == i++){ this.SetContainer(menu, position); break; }
	}
  },
  //容器设置(菜单结构, 位置)
  SetContainer: function(menu, position) {
	var oContainer = this.Container[this._index];
	
	//设置容器
	oContainer.innerHTML = ""; oContainer.index = -1; oContainer.style.visibility = "hidden";
	
	if(menu.length > 0){
		//设置菜单
		this.SetMenu(menu);
		
		//容器定位
		//offset取值会有偏差,要注意
		var o = this._onmenu, iLeft = o.offsetLeft, iTop = o.offsetTop;
		//注意如果display为none的话取不到offset值,所以要用visibility
		switch (position.toLowerCase()) {
			case "up" :
				iTop -= oContainer.offsetHeight;
				break;
			case "down" :
				iTop += o.offsetHeight;
				break;
			case "left" :
				iLeft -= oContainer.offsetWidth;
				break;
			case "right" :
			default :
				iLeft += o.offsetWidth;
		}
		while (o.offsetParent) { o = o.offsetParent; iLeft += o.offsetLeft; iTop += o.offsetTop; }
		oContainer.style.left = iLeft + "px"; oContainer.style.top = iTop + "px";
		oContainer.style.visibility = "visible";
	}
	
	//隐藏不需要的容器
	for(var i = this._index + 1, len = this.Container.length; i < len; i++){ this.Container[i].style.visibility = "hidden";  }
  },
  //菜单设置(菜单结构)
  SetMenu: function(menu) {
	var oThis = this, index = this._index, oContainer = this.Container[index];
	Each(menu, function(o, i){
		var oMenu = document.createElement(oThis.Tag);
		oMenu.innerHTML = o.txt;
		oMenu.onmouseover = function(){
			clearTimeout(oThis._timerMenu);
			
			//重新设置菜单
			oThis._timerMenu = setTimeout(function(){
				oContainer.index = i; oThis._onmenu = oMenu; oThis._index = index + 1;  oThis.Set();
			}, oThis.Delay);
			
			//重新设置样式
			//为解决设置延时后样式的问题每次都全部重新设置
			Each(oThis.Container, function(o, i){
				if(i > index) return;
				Each(o.getElementsByTagName(oThis.Tag), function(o){ o.className = oThis.Class; });
				if(i == index){
					oMenu.className = oThis.onClass;
				} else if(o.index >= 0) {
					o.getElementsByTagName(oThis.Tag)[o.index].className = oThis.onClass;
				} else return;
			});
		}
		oContainer.appendChild(oMenu);
	});	
  },
  //隐藏菜单
  Hide: function() {
	var oThis = this;
	//除第一个外隐藏
	Each(this.Container, function(o, i){
		if(i == 0){
			Each(o.getElementsByTagName(oThis.Tag), function(o, i){ o.className = oThis.Class; })
		} else { o.style.visibility = "hidden"; }
		o.index = -1;
	});
	
	//显示select
	Each(document.getElementsByTagName("select"), function(o){ o.style.visibility = "visible"; })
  },
  //添加菜单(一个菜单结构)
  Add: function(arrMenu) {
	this._menu.push(arrMenu); this.Ini();
  },
  //删除菜单
  Delete: function(index) {
	if(index < 0 || index >= this._menu.length) return;
	for(var i = index, len = this._menu.length - 1; i < len; i++){ this._menu[i] = this._menu[i + 1]; }
		this._menu.pop(); this.Ini();
  }
};


window.onload=function(){
	
	var menu = [
		{'txt': '1 <a href="http://shundebk.cn/">link</a>' },
		{'txt': '2 →', 'menu': [
			{'txt': '2_1'},
			{'txt': '2_2'}
		]},
		{'txt': '3 →', 'menu': [
			{'txt': '3_1 ↑', 'position': 'up', 'menu': [
				{'txt': '3_1_1'},
				{'txt': '3_1_2'}
			]},
			{'txt': '3_2'}
		]},
		{'txt': '4 →', 'menu': [
			{'txt': '4_1 ↓', 'position': 'down', 'menu': [
				{'txt': '4_1_1 →', 'menu': [
					{'txt': '4_1_1_1'}
				]}
			]}
		]},
		{'txt': '5 →', 'menu': [
			{'txt': '5_1 →', 'menu': [
				{'txt': '5_1_1 ↓', 'position': 'down', 'menu': [
					{'txt': '5_1_1_1 ←', 'position': 'left', 'menu': [
						{'txt': '5_1_1_1_1'}
					]}
				]}
			]}
		]}
	];
	
	var container=["idMenu1"];
	
	var cs = new CascadeMenu(container, menu, { Delay: 200, onClass: "on" });
	
	////////////////test2
	
	var menu2 = [
		{'txt': '<a href="#">1 ↓</a>', 'position': 'down', 'menu': [
			{'txt': '<a href="#">1_1</a>'},
			{'txt': '<a href="#">1_2</a>'}
		]},
		{'txt': '<a href="#">2 ↓</a>', 'position': 'down', 'menu': [
			{'txt': '<a href="#">2_1</a>'},
			{'txt': '<a href="#">2_2 →</a>', 'menu': [
				{'txt': '<a href="#">2_2_1</a>'},
				{'txt': '<a href="#">2_2_2</a>'}
			]}
		]},
		{'txt': '<a href="#">3 ↓</a>', 'position': 'down', 'menu': [
			{'txt': '<a href="#">3_1 →</a>', 'menu': [
				{'txt': '<a href="#">3_1_1 →</a>', 'menu': [
					{'txt': '<a href="#">3_1_1_1</a>'}
				]}
			]}
		]}
	];
	
	var container2=["idMenu2", "idMenu2_1", "idMenu2_2", "idMenu2_3", "idMenu2_4", "idMenu2_5", "idMenu2_6"];
	
	var cs2 = new CascadeMenu(container2, menu2, { Delay: 200, onClass: "on" });
	
	$("btnA").onclick=function(){cs2.Delay=0;}
	$("btnD").onclick=function(){cs2.Delay=500;}
	
	$("btnB").onclick=function(){
		cs2.Add(
			{'txt': '<a href="#">+ ↓</a>', 'position': 'down', 'menu': [
				{'txt': '<a href="#">+_1 ←</a>', 'position': 'left', 'menu': [
					{'txt': '<a href="#">+_1_1 ↓</a>', 'position': 'down', 'menu': [
						{'txt': '<a href="#">+_1_1_1 →</a>', 'menu': [
							{'txt': '<a href="#">+_1 ↓</a>', 'position': 'down', 'menu': [
								{'txt': '<a href="#">+_1_1_1 →</a>', 'menu': [
									{'txt': '<a href="#">★</a>'}
								]}
							]}
						]}
					]}
				]}
			]}
		)
	}
	
	$("btnC").onclick=function(){
		cs2.Delete(1)
	}
}
</script>
<style type="text/css">
.container {
	width:100px;
}
.container div {
	width:100px;
	background:#CCCCCC;
	line-height:30px;
	border:1px solid #000000;
}
.on {
	font-weight:bold;
}
.container2 {
	width:100px;
	text-align:center;
}
.container2 div {
	width:100px;
	line-height:30px;
}
.container2 a {
	text-decoration:none;
	display:block;
	border:1px solid #d4d4d3;
	background:#e6e6e6;
	color:#000000;
}
.container2 .on a {
	background:#ffebac;
	color:#982e00;
	border-color:#ffb200;
}
#idMenu2 {
	clear:both;
	width:auto;
}
#idMenu2 div {
	float:left;
}
#idMenu2_6 a {
	background-color:red;
	border-color:red;
	color:#ffb200;
}
</style>
</head>
<body>
<div></div>
<br />
<br />
<br />
<div>
  <input type="button" value="添加菜单" />
  <input type="button" value="减少菜单(第二个)" />
  <input type="button" value="不延迟" />
  <input type="button" value="延迟500" />
</div>
<br />
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</body>
</html>


Transfer from: http://www.cnblogs.com/cloudgamer/archive/2008/06/28/1231557.html #

Black hair: http://heisetoufa.javaeye.com/
Digg Technorati StumbleUpon Mixx del.icio.us Reddit BlinkList Furl YahooMyWeb feedburner

Tags: lt (RSS), amp (RSS), principle (RSS), div (RSS), containers (RSS), menu object (RSS), linkage (RSS), container object (RSS), value menu (RSS), mouseover (RSS), timer (RSS), slide show (RSS), separately (RSS), layer by layer (RSS)

Permalink: http://www.codeweblog.com/javascript-html-js-many-custom-class-linkage-floating-menu-js-produced-menu/

Leave a reply