Js實(shí)現(xiàn)京東無(wú)延遲菜單效果(demo)

先來(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>&gt</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>&gt</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>&gt</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>&gt</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>&gt</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>&gt</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>&gt</i></a>
                </dt>
                <dd>
                    <a href="#">筆記本</a>
                    <a href="#">游戲本</a>
                    <a href="#">平板電腦</a>
                </dd>
                <dt>
                    <a href="#">電腦配件<i>&gt</i></a>
                </dt>
                <dd>
                    <a href="#">顯示器</a>
                    <a href="#">CPU</a>
                    <a href="#">主板</a>
                </dd>
                <dt>
                    <a href="#">外設(shè)產(chǎn)品<i>&gt</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>&gt</i></a>
                </dt>
                <dd>
                    <a href="#">烹飪鍋具</a>
                    <a href="#">刀剪配件</a>
                    <a href="#">廚房配件</a>
                    <a href="#">水具酒具</a>
                </dd>
                <dt>
                    <a href="#">家紡<i>&gt</i></a>
                </dt>
                <dd>
                    <a href="#">床品套件</a>
                    <a href="#">被子</a>
                    <a href="#">枕芯</a>
                    <a href="#">蚊帳</a>
                </dd>
                <dt>
                    <a href="#">生活日用<i>&gt</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>&gt</i></a>
                </dt>
                <dd>
                    <a href="#">商城同款</a>
                    <a href="#">當(dāng)季熱賣</a>
                    <a href="#">2017新品</a>
                    <a href="#">連衣裙</a>
                </dd>
                <dt>
                    <a href="#">男裝<i>&gt</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>&gt</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

原博地址http://www.cnblogs.com/6kou/p/jd.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市钻蹬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凭需,老刑警劉巖脉让,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異功炮,居然都是意外死亡溅潜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門薪伏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)滚澜,“玉大人,你說(shuō)我怎么就攤上這事嫁怀∩杈瑁” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵塘淑,是天一觀的道長(zhǎng)萝招。 經(jīng)常有香客問(wèn)我,道長(zhǎng)存捺,這世上最難降的妖魔是什么槐沼? 我笑而不...
    開(kāi)封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任曙蒸,我火速辦了婚禮,結(jié)果婚禮上岗钩,老公的妹妹穿的比我還像新娘纽窟。我一直安慰自己,他們只是感情好兼吓,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布臂港。 她就那樣靜靜地躺著,像睡著了一般视搏。 火紅的嫁衣襯著肌膚如雪审孽。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天浑娜,我揣著相機(jī)與錄音瓷胧,去河邊找鬼。 笑死棚愤,一個(gè)胖子當(dāng)著我的面吹牛搓萧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宛畦,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瘸洛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了次和?” 一聲冷哼從身側(cè)響起反肋,我...
    開(kāi)封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎踏施,沒(méi)想到半個(gè)月后石蔗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡畅形,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年养距,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片日熬。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡棍厌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出竖席,到底是詐尸還是另有隱情耘纱,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布毕荐,位于F島的核電站束析,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏憎亚。R本人自食惡果不足惜员寇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一弄慰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丁恭,春花似錦、人聲如沸斋日。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)恶守。三九已至第献,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兔港,已是汗流浹背庸毫。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衫樊,地道東北人飒赃。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像科侈,于是被迫代替她去往敵國(guó)和親载佳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • JSLearn-ES6 'ES6語(yǔ)法學(xué)習(xí)' JavaScript基礎(chǔ)知識(shí)剖析 01 變量與原型 01-01 變量類...
    _Elmer閱讀 668評(píng)論 0 0
  • 轉(zhuǎn)載請(qǐng)著名出處 GitHub-TYRMars 文章Github地址 JavaScript基礎(chǔ)知識(shí)剖析 01 01-...
    TYRMars閱讀 554評(píng)論 0 7
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,743評(píng)論 25 707
  • 開(kāi)發(fā)基本菜單結(jié)構(gòu)臀栈,普通二級(jí)菜單效果蔫慧,加入延遲解決移動(dòng)問(wèn)題,解決延遲引入的新問(wèn)題 function.js封裝的函數(shù): }
    穆熙沐閱讀 1,232評(píng)論 4 20
  • 婷婷: 一轉(zhuǎn)眼权薯,你已是大姑娘了姑躲, 還記的21年前給你剪胎毛的樣子, 瘦瘦的盟蚣,頭皮都能拎起來(lái)黍析。 而今的你卻已大變樣了...
    隨緣隨意成長(zhǎng)屋閱讀 649評(píng)論 0 2