index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<div class="menu-wrap">
<div class="main">
<ul class="main-list">
<li class="main-item">
<a href="javascript:;">菜单1</a>
</li>
<li class="main-item">
<a href="javascript:;">菜单2</a>
</li>
<li class="main-item">
<a href="javascript:;">菜单3</a>
</li>
<li class="main-item">
<a href="javascript:;">菜单4</a>
</li>
<li class="main-item">
<a href="javascript:;">菜单5</a>
</li>
<li class="main-item">
<a href="javascript:;">菜单6</a>
</li>
<li class="main-item">
<a href="javascript:;">菜单7</a>
</li>
<li class="main-item">
<a href="javascript:;">菜单8</a>
</li>
<li class="main-item">
<a href="javascript:;">菜单9</a>
</li>
<li class="main-item">
<a href="javascript:;">菜单10</a>
</li>
</ul>
</div>
<div class="sub hide">
<ul class="sub-list">
<li class="sub-item active">
子菜单1
</li>
<li class="sub-item">
子菜单2
</li>
<li class="sub-item">
子菜单3
</li>
<li class="sub-item">
子菜单4
</li>
<li class="sub-item">
子菜单5
</li>
<li class="sub-item">
子菜单6
</li>
<li class="sub-item">
子菜单7
</li>
<li class="sub-item">
子菜单8
</li>
<li class="sub-item">
子菜单9
</li>
<li class="sub-item">
子菜单10
</li>
</ul>
</div>
</div>
<script src="js/utils.js"></script>
<script src="js/index.js"></script>
</body>
</html>
index.css
ul {
padding: 0;
margin: 0;
list-style: none;
}
a {
text-decoration: none;
}
.menu-wrap {
position: relative;
width: 200px;
height: 440px;
background-color: #424242;
margin: 50px;
}
.menu-wrap .main {
height: 100%;
}
.menu-wrap .main .main-item {
height: 44px;
}
.menu-wrap .main .main-item a {
display: block;
height: 100%;
text-align: center;
line-height: 44px;
color: #fff;
}
.menu-wrap .main .main-item.active a {
background-color: #666;
color: orange;
}
.menu-wrap .sub{
position: absolute;
top: 0;
left: 200px;
width: 440px;
height: 440px;
background-color: #eeeeee;
}
.menu-wrap .sub.hide {
display: none;
}
.menu-wrap .sub .sub-item {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
line-height: 440px;
text-align: center;
font-size: 50px;
}
.menu-wrap .sub .sub-item.active {
display: block;
}
index.js
window.onload = function () {
init();
}
function init() {
initMenu()
}
var initMenu = (function () {
var oMenu = document.getElementsByClassName('menu-wrap')[0],
oMenuItems = oMenu.getElementsByClassName('main-item'),
menuLen = oMenuItems.length,
oSub = document.getElementsByClassName('sub')[0],
oSubItems = oSub.getElementsByClassName('sub-item'),
subLen = oSubItems.length,
menuItem,
subItem,
isFrist = true,
isInSub = false,
t = null,
mousePoses = [];
addEvent(oMenu, 'mouseenter', function () {
addEvent(document, 'mousemove', mouseMove)
})
addEvent(oMenu, 'mouseleave', menuMouseOut);
addEvent(oSub, 'mouseenter', function () {
isInSub = true;
});
addEvent(oSub, 'mouseleave', function () {
isInSub = false;
})
for (var i = 0; i < menuLen; i++) {
menuItem = oMenuItems[i];
addEvent(menuItem, 'mouseenter', menuItemMouseEnter)
}
function menuItemMouseEnter(e) {
var e = e || window.event,
tar = e.target || e.srcElement,
thisIdx = Array.prototype.indexOf.call(oMenuItems, tar),
posLen = mousePoses.length,
curPos = mousePoses[posLen - 1] || { x: 0, y: 0 },
lastPos = mousePoses[posLen - 2] || { x: 0, y: 0 },
toDelay = doTimeout(lastPos, curPos);
console.log(toDelay);
oSub.className = 'sub'
if (t) {
clearTimeout(t);
}
if (!isFrist) {
if (toDelay) {
t = setTimeout(function () {
if (isInSub) {
return;
}
addAcitve(thisIdx);
t = null;
}, 300);
} else {
addAcitve(thisIdx);
}
} else {
addAcitve(thisIdx);
isFrist = false;
}
}
function addAcitve(index) {
removeAllActive();
oMenuItems[index].className += ' active';
oSubItems[index].className += ' active';
}
function removeAllActive() {
for (var i = 0; i < menuLen; i++) {
menuItem = oMenuItems[i];
subItem = oSubItems[i];
menuItem.className = 'main-item';
subItem.className = 'sub-item'
}
}
function menuMouseOut() {
oSub.className += ' hide'
removeAllActive();
removeEvent(document, 'mousemove', mouseMove)
}
function mouseMove(e) {
var e = e || winow.event;
mousePoses.push({
x: pagePos(e).X,
y: pagePos(e).Y
})
if (mousePoses.length > 2) {
mousePoses.shift();
}
}
function doTimeout(lastPos, curPos) {
var TL = {
x: getStyles(oMenu, 'margin-left') + getStyles(oMenu, 'width'),
y: getStyles(oMenu, 'margin-top')
},
BL = {
x: getStyles(oMenu, 'margin-left') + getStyles(oMenu, 'width'),
y: getStyles(oMenu, 'margin-top') + getStyles(oMenu, 'height')
}
return pointInTriangle({
curPos: curPos,
lastPos: lastPos,
topLeft: TL,
bottomLeft: BL
})
}
});
utils.js
// 添加事件处理函数兼容写法
function addEvent(el, type, fn) {
if (el.addEventListener) {
el.addEventListener(type, fn, false)
} else if (el.attachEvent) {
el.attachEvent('on' + type, function () {
fn.call(el);
})
} else {
el['on' + type] = fn;
}
}
// 删除事件处理函数
function removeEvent(elem, type, fn) {
if (elem.addEventListener) {
elem.removeEventListener(type, fn, false);
} else if (elem.attachEvent) {
elem.attachEvent('on' + type, fn);
} else {
elem['on' + type] = null;
}
}
// 取消冒泡行为
function cancleBubble(e) {
var e = e || window.event;
if (e.stopPropagation) {
e.stopPropagation();
} else {
e.cancleBubble = true;
}
}
// 阻止默认行为
function preventDefaultEvent(e) {
var e = e || window.event;
if (e.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
// 获取文档距离
function pagePos(e) {
var sLeft = getScrollOffset().left,
sTop = getScrollOffset().top,
cLeft = document.documentElement.clientLeft || 0,
cTop = document.documentElement.clientTop || 0;
return {
X: e.clientX + sLeft - cLeft,
Y: e.clientY + sTop - cTop
}
}
// 获取滚动条距离
function getScrollOffset() {
if (window.pageXOffset) {
return {
left: window.pageXOffset,
top: window.pageYOffset
}
} else {
return {
left: document.body.scrollLeft + document.documentElement.scrollLeft,
top: document.body.scrollTop + document.documentElement.scrollTop
}
}
}
// 获取窗口宽高
function getViewportSize() {
if (window.innerWidth) {
return {
width: window.innerWidth,
height: window.innerHeight
}
} else {
if (document.compatMode === 'BackCompat') {
return {
width: document.body.clientWidth,
height: document.body.clientHeight
}
}
else {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
}
}
}
}
// 获取文档宽高
function getScrollSize() {
if (document.body.scrollWidth) {
return {
width: document.body.scrollWidth,
height: document.body.scrollHeight
}
} else {
return {
width: document.documentElement.scrollWidth,
height: document.documentElement.scrollHeight
}
}
}
// 选择子元素
function elemChildren(node) {
var temp = {
'length': 0,
'splice': Array.prototype.splice
},
len = node.childNodes.length;
for (var i = 0; i < len; i++) {
var childItem = node.childNodes[i];
if (childItem.nodeType === 1) {
temp[temp.length] = childItem;
temp['length']++;
}
}
return temp;
}
// 寻找父级元素
function elemParent(node, n) {
var type = typeof (n);
if (type === 'unfefined') {
return node.parentNode;
} else if (n <= 0 || type !== 'number') {
return undefined;
}
while (n) {
node = node.parentNode;
n--;
}
return node;
}
// 获取样式属性
function getStyles(elem, prop) {
if (window.getComputedStyle) {
if (prop) {
return parseInt(window.getComputedStyle(elem, null)[prop]); // null 伪类元素
} else {
return window.getComputedStyle(elem, null);
}
} else {
if (prop) {
return parseInt(elem.currentStyle[prop]);
} else {
return elem.currentStyle;
}
}
}
// 判断点是否在一个三角形内
var pointInTriangle = (function () {
function vec(a, b) {
return {
x: b.x - a.x,
y: b.y - a.y
}
}
function vecProduct(v1, v2) {
return v1.x * v2.y - v2.x * v1.y;
}
function sameSymbols(a, b) {
return (a ^ b) >= 0;
}
return function (opt) {
var PA = vec(opt.curPos, opt.lastPos),
PB = vec(opt.curPos, opt.topLeft),
PC = vec(opt.curPos, opt.bottomLeft),
R1 = vecProduct(PA, PB),
R2 = vecProduct(PB, PC),
R3 = vecProduct(PC, PA);
return sameSymbols(R1, R2) && sameSymbols(R2, R3)
}
})();