先來(lái)理清思路
1.開(kāi)發(fā)基本的菜單結(jié)構(gòu)
2.開(kāi)發(fā)普通的二級(jí)菜單效果
3.假如延遲解決移動(dòng)問(wèn)題 切換子菜單時(shí)候巫击,用setTimeout設(shè)置延遲 debounce去抖技 在事件被頻繁觸發(fā)是敦迄,只執(zhí)行一次處理
4.解決延遲引入的新問(wèn)題 跟蹤鼠標(biāo)的移動(dòng) 用鼠標(biāo)當(dāng)前位置链蕊,和鼠標(biāo)上一次位置與子菜單上下邊緣的三角形區(qū)域進(jìn)行比較 運(yùn)用到向量 二位向量叉乘公式 用叉乘法判斷點(diǎn)在三角形內(nèi)
最終效果:鼠標(biāo)自然的移動(dòng)和點(diǎn)擊到子菜單 切換時(shí)無(wú)延遲
html代碼 1.開(kāi)發(fā)基本的菜單結(jié)構(gòu)
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>京東菜單無(wú)刷新</title>
<script src="js/jquery-1.7.2.min.js"></script>
<script src="js/mche.js"></script>
<script src="js/function.js"></script>
<style>
.wrap{
position:relative;
width:200px;
left:50px;
top:50px;
}
ul{
padding:15px;
margin:9;
list-style:none;
background:#6c6669;
color:#ffffff;
border-right-width:0;
}
/*水平居中*/
li{
display:block;
height:30px;
line-height: 30px;
padding-left:12px;
cursor:pointer;
font-size: 14px;
position:relative;
}
/*鼠標(biāo)移動(dòng)上去的背景色*/
li.active{
background:#999395;
}
/*js可以很好地調(diào)用類,一般效果css實(shí)現(xiàn)就好*/
li span:hover{
color:#c81623;
}
/*隱藏的類*/
.none{
display: none;
}
/*二級(jí)菜單*/
#sub{
width:600px;
position: absolute;
border:1px solid #f7f7f7;
background:#f7f7f7;
box-shadow:2px 0 rgba(0,0,0,.3);
left: 200px;
top:0;
box-sizing:border-box;
margin: 0px;
padding:10px;
}
.sub-content a{
font-style:12px;
color:#666;
text-decoration:none;
}
.sub-content dd a{
border-left:1px solid #e0e0e0;
padding:0 1px;
margin:4px 0;
}
.sub-content dl {
overflow:hidden;
}
.sub-content dt{
float: left;
width:70px;
font-weight: bold;
clear:left;
position:relative;
}
.sub-content dd {
float: left;
margin-left: 5px;
border-top:1px solid #eee;
margin-bottom: 5px;
}
.sub-content dt i{
width:4px;
height: 14px;
font:400 9px/14px consolas;
position: absolute;
right:5px;
top:5px;
}
</style>
</head>
<body>
<div class="wrap" id="test">
<ul>
<li data-id="a">
<span>家用電器</span>
</li>
<li data-id="b">
<span>手機(jī) / 運(yùn)營(yíng)商 / 數(shù)碼</span>
</li>
<li data-id="c">
<span>電腦辦公 / 辦公</span>
</li>
<li data-id="d">
<span>家居 / 家具 / 家裝 / 廚具</span>
</li>
<li data-id="e">
<span>男裝 / 女裝 / 童裝 / 內(nèi)衣 </span>
</li>
<li data-id="f">
<span>美妝個(gè)護(hù) / 寵物 </span>
</li>
<li data-id="g">
<span>女鞋 / 箱包 / 鐘表 / 珠寶 </span>
</li>
<li data-id="h">
<span>男鞋 / 運(yùn)動(dòng) / 戶外</span>
</li>
<li data-id="i">
<span>汽車 / 汽車用品 </span>
</li>
</ul>
<div id="sub" class="none">
<div id="a" class="sub-content none">
<dl>
<dt>
<a href="#">電視<i>></i></a>
</dt>
<dd>
<a href="#">曲面電視</a>
<a href="#">超薄電視</a>
<a href="#">HDR電視</a>
<a href="#">DLED電視</a>
</dd>
<dt>
<a href="#">空調(diào)<i>></i></a>
</dt>
<dd>
<a href="#">掛壁式空調(diào)</a>
<a href="#">柜式空調(diào)</a>
<a href="#">中央空調(diào)</a>
<a href="#">以舊換新</a>
</dd>
<dt>
<a href="#">洗衣機(jī)<i>></i></a>
</dt>
<dd>
<a href="#">滾筒式洗衣機(jī)</a>
<a href="#">洗烘一體機(jī)</a>
<a href="#">波輪洗衣機(jī)</a>
<a href="#">迷你洗衣機(jī)</a>
</dd>
</dl>
</div>
<div id="b" class="sub-content none">
<dl>
<dt>
<a href="#">手機(jī)通訊<i>></i></a>
</dt>
<dd>
<a href="#">手機(jī)</a>
<a href="#">對(duì)講機(jī)</a>
<a href="#">以舊換新</a>
<a href="#">手機(jī)維修</a>
</dd>
<dt>
<a href="#">運(yùn)營(yíng)商<i>></i></a>
</dt>
<dd>
<a href="#">合約機(jī)</a>
<a href="#">選號(hào)機(jī)</a>
<a href="#">固定電話</a>
<a href="#">辦寬帶</a>
</dd>
<dt>
<a href="#">手機(jī)配件<i>></i></a>
</dt>
<dd>
<a href="#">手機(jī)殼</a>
<a href="#">貼膜</a>
<a href="#">手機(jī)存儲(chǔ)卡</a>
<a href="#">數(shù)據(jù)線</a>
</dd>
</dl>
</div>
<div id="c" class="sub-content none">
<dl>
<dt>
<a href="#">電腦整機(jī)<i>></i></a>
</dt>
<dd>
<a href="#">筆記本</a>
<a href="#">游戲本</a>
<a href="#">平板電腦</a>
</dd>
<dt>
<a href="#">電腦配件<i>></i></a>
</dt>
<dd>
<a href="#">顯示器</a>
<a href="#">CPU</a>
<a href="#">主板</a>
</dd>
<dt>
<a href="#">外設(shè)產(chǎn)品<i>></i></a>
</dt>
<dd>
<a href="#">鼠標(biāo)</a>
<a href="#">鍵盤</a>
<a href="#">鍵盤套餐</a>
</dd>
</dl>
</div>
<div id="d" class="sub-content none">
<dl>
<dt>
<a href="#">廚具<i>></i></a>
</dt>
<dd>
<a href="#">烹飪鍋具</a>
<a href="#">刀剪配件</a>
<a href="#">廚房配件</a>
<a href="#">水具酒具</a>
</dd>
<dt>
<a href="#">家紡<i>></i></a>
</dt>
<dd>
<a href="#">床品套件</a>
<a href="#">被子</a>
<a href="#">枕芯</a>
<a href="#">蚊帳</a>
</dd>
<dt>
<a href="#">生活日用<i>></i></a>
</dt>
<dd>
<a href="#">收納用品</a>
<a href="#">雨傘雨具</a>
<a href="#">凈化除味</a>
<a href="#">浴室用品</a>
</dd>
</dl>
</div>
<div id="e" class="sub-content none">
<dl>
<dt>
<a href="#">女裝<i>></i></a>
</dt>
<dd>
<a href="#">商城同款</a>
<a href="#">當(dāng)季熱賣</a>
<a href="#">2017新品</a>
<a href="#">連衣裙</a>
</dd>
<dt>
<a href="#">男裝<i>></i></a>
</dt>
<dd>
<a href="#">商城同款</a>
<a href="#">當(dāng)季熱賣</a>
<a href="#">2017新品</a>
<a href="#">牛仔褲</a>
</dd>
</dl>
</div>
<div id="f" class="sub-content none">
<dl>
<dt>
<a href="#">面部護(hù)膚<i>></i></a>
</dt>
<dd>
<a href="#">補(bǔ)水保濕</a>
<a href="#">卸妝</a>
<a href="#">潔面</a>
</dd>
</dl>
</div>
</div>
</ul>
</body>
</html>
2.完成開(kāi)發(fā)普通的二級(jí)菜單效果
3.用setTimeout設(shè)置延遲 debounce去抖技 在事件被頻繁觸發(fā)時(shí)糠聪,只執(zhí)行一次處理
$(document).ready(function(){
var sub = $('#sub')
var activeRow
var activeMenu
var timer
var mouseInSub = false
sub.on('mouseenter',function(e){
mouseInSub = true
}).on('mouseleave',function(e){
mouseInSub = false
})
var mouseTrack = []
var moveHandler = function(e){
mouseTrack.push({
x:e.pageX,
y:e.pageY
})
if(mouseTrack.length > 3){
mouseTrack.shift()
}
}
$('#test')
.on('mouseenter',function(e){
sub.removeClass('none')
$(document).bind('mousemove',moveHandler)
})
.on('mouseleave',function(e){
sub.addClass('none')
if(activeRow){
activeRow.removeClass('active')
activeRow = null;
}
if(activeMenu){
activeMenu.addClass('none')
activeMenu = null;
}
//解綁
$(document).unbind('mousemove',moveHandler)
})
.on('mouseenter','li',function(e){
if(!activeRow){
activeRow = $(e.target).addClass('acrive')
activeMenu = $('#'+activeRow.data('id'))
activeMenu.removeClass('none')
return
}
//清除
if(timer){
clearTimeout(timer)
}
//鼠標(biāo)當(dāng)前坐標(biāo)
var currMousePos = mouseTrack[mouseTrack.length - 1]
//上次的坐標(biāo)
var leftCorner = mouseTrack[mouseTrack.length-2]
var delay = needDelay(sub,leftCorner,currMousePos)
if(delay){
// 時(shí)間觸發(fā),設(shè)置一個(gè)緩沖期
timer = setTimeout(function(){
//判斷
if(mouseInSub){
return
}
activeRow.removeClass('active')
activeMenu.addClass('none')
activeRow = $(e.target)
activeRow.addClass('active')
activeMenu = $('#'+ activeRow.data('id'))
activeMenu.removeClass('none')
timer = null
}, 300)
}else{
var prevActiveRow = activeRow
var prevActiveMenu = activeMenu
activeRow = $(e.target)
activeMenu = $('#' + activeRow.data('id'))
prevActiveRow.removeClass('active')
prevActiveMenu.addClass('none')
activeRow.addClass('active')
activeMenu.removeClass('none')
}
})
})
4. 解決延遲引入的新問(wèn)題
function sameSign(a,b){
return (a ^ b) >= 0
}
function vector(a,b){
return{
x:b.x - a.x,
y:b.y - a.y
}
}
function vectorProduct(v1,v2){
return v1.x * v2.y - v2.x * v1.y
}
function isPointInTrangle(p,a,b,c){
var pa = vector(p,a)
var pb = vector(p,b)
var pc = vector(p,c)
var t1 = vectorProduct(pa,pb)
var t2 = vectorProduct(pb,pc)
var t3 = vectorProduct(pc,pa)
return sameSign(t1,t2) && sameSign(t2,t3)
}
function needDelay(elem,leftCorner,currMousePos){
var offset = elem.offset()
var topLeft = {
x:offset.left,
y:offset.top
}
var bottomLeft = {
x:offset.left,
y:offset.top + elem.height()
}
return isPointInTrangle(currMousePos,leftCorner,topLeft,bottomLeft)
}
1105168-20170602184106164-70570130.gif