js模仿京東無(wú)延遲菜單效果

開發(fā)基本菜單結(jié)構(gòu),
普通二級(jí)菜單效果,
加入延遲解決移動(dòng)問(wèn)題,
解決延遲引入的新問(wèn)題

效果圖.png
<style type="text/css">
    .wrap{
        position: relative;width: 200px;top: 50px;left: 50px
    }
    ul{
        padding: 15px 0;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;
    }
    /*用類控制有利于JS增刪類*/

    li.active{
        background: #999395;
    }
    li span:hover{
        color: #c81623;
    }
    .none{
        display: none
    }
    #sub{
        width: 600px;position: absolute;border: 1px solid #f7f7f7;background: #f7f7f7;box-shadow: 2px 0 5px rgba(0,0,0,.3);top: 0;left: 200px;box-sizing: border-box;margin: 0;padding: 10px;
    }
    .sub_content a{
        font-size: 12px;color: #666;text-decoration: none;
    }
    .sub_content dd a{
        border-left: 1px solid #e0e0e0;padding: 0 10px;margin: 4px 0;
    }
    /*清除浮動(dòng) BFC*/
    .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>

<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>
    </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="#">國(guó)產(chǎn)品牌</a>
                    <a href="#">互聯(lián)網(wǎng)品牌</a>
                </dd>
            </dl>
            <dl>
                <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>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">洗衣機(jī)<i>></i></a>
                </dt>
                <dd>
                    <a href="#">波輪洗衣機(jī)</a>
                    <a href="#">烘托一體機(jī)</a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">冰箱<i>></i></a>
                </dt>
                <dd>
                    <a href="#">多門</a>
                    <a href="#">對(duì)開門</a>
                    <a href="#">三門</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>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">手機(jī)配件<i>></i></a>
                </dt>
                <dd>
                    <a href="#">合資品牌</a>
                    <a href="#">國(guó)產(chǎn)品牌</a>
                    <a href="#">互聯(lián)網(wǎng)品牌</a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">運(yùn)營(yíng)商<i>></i></a>
                </dt>
                <dd>
                    <a href="#">合約機(jī)</a>
                    <a href="#">固定電話</a>
                    <a href="#">寬帶</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>
            </dl>
            <dl>
                <dt>
                    <a href="#">電腦配件<i>></i></a>
                </dt>
                <dd>
                    <a href="#">顯示器</a>
                    <a href="#">CPU</a>
                    <a href="#">主板</a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">外設(shè)產(chǎn)品<i>></i></a>
                </dt>
                <dd>
                    <a href="#">鼠標(biāo)</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>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">家紡<i>></i></a>
                </dt>
                <dd>
                    <a href="#">被子</a>
                    <a href="#">枕芯</a>
                    <a href="#">蚊帳</a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">生活日用<i>></i></a>
                </dt>
                <dd>
                    <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="#">商場(chǎng)同款</a>
                    <a href="#">當(dāng)即熱賣</a>
                    <a href="#">2017新品</a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">男裝<i>></i></a>
                </dt>
                <dd>
                    <a href="#">牛仔褲</a>
                    <a href="#">休閑褲</a>
                    <a href="#">襯衫</a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">內(nèi)衣<i>></i></a>
                </dt>
                <dd>
                    <a href="#">大碼內(nèi)衣</a>
                    <a href="#">打底衫</a>
                </dd>
            </dl>
        </div>  
    </div>
</div>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src='function.js'></script>
<script type="text/javascript">
    // 事件代理方式進(jìn)行綁定mouseenter/mouseover的區(qū)別:
    // mouseover和mouseout,如果鼠標(biāo)移動(dòng)到子元素上,即便沒(méi)有離開父元素,也會(huì)觸發(fā)父元素的mouseout事件,mouseenter/mouseleave,如果鼠標(biāo)沒(méi)有離開父元素,在子元素上任意移動(dòng),也不會(huì)觸發(fā)mouseleave事件
    $(document).ready(function(){
        var sub = $("#sub");
        var activeRow;//當(dāng)前激活的一級(jí)菜單行
        var activeMenu;//對(duì)應(yīng)的二級(jí)菜單
        var timer;//計(jì)時(shí)器
        var mouseInSub = false;//鼠標(biāo)是否在子菜單

        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');//二級(jí)菜單顯示
                $(document).on('mousemove',moveHandler)
            })
            .on('mouseleave',function(e){
                sub.addClass('none');//二級(jí)菜單隱藏
                // console.log(activeRow)
                if (activeRow) {
                    activeRow.removeClass('active');
                    activeRow = null;
                }
                if(activeMenu){
                    activeMenu.addClass('none');
                    activeMenu = null;
                }
                $(document).unbind('mousemove',moveHandler)//解綁mousemove
            })
            .on('mouseenter','li',function(e){//事件代理方式綁定

                if (!activeRow) {
                    activeRow = $(e.target).addClass('active');
                    activeMenu = $('#'+activeRow.data('id'));
                    activeMenu.removeClass('none');
                    return
                }
                // 加入延遲優(yōu)化
            // 切換子菜單的時(shí)候,用setTimeout設(shè)置延遲。(但是不能迅速切換)
            // debounce去抖技術(shù),在事件頻繁觸發(fā)時(shí),只執(zhí)行一次處理,最后一次(計(jì)時(shí)器還沒(méi)執(zhí)行的時(shí)候,清除計(jì)時(shí)器,并在計(jì)時(shí)器設(shè)置空)
                if (timer) {
                    clearTimeout(timer)
                }

                var currMousePos = mouseTrack[mouseTrack.length - 1]
                var leftCorner = mouseTrack[mouseTrack.length - 2]

                var delay = needDelay(sub,leftCorner,currMousePos)
                if (delay) {
                    timer = setTimeout(function(){
                        if (mouseInSub) {
                            return
                        }
                        //li之間切換,清除之前狀態(tài)
                        activeRow.removeClass('active');
                        activeMenu.addClass('none');
                        // 指向當(dāng)前l(fā)i
                        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')
                }
                
                
            })
            // 基于用戶行為預(yù)測(cè)的切換技術(shù)
            // 跟蹤鼠標(biāo)的移動(dòng)
            // 用鼠標(biāo)當(dāng)前位置,和鼠標(biāo)上一次位置與子菜單上下邊緣形成的三角形區(qū)域進(jìn)行比較

    })
</script>

function.js封裝的函數(shù):

    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
  }

  // 判斷點(diǎn)在三角形內(nèi)
  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(pa,pc)
    var t3 = vectorProduct(pb,pc)

    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)

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,811評(píng)論 25 708
  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 7,807評(píng)論 2 17
  • 1.幾種基本數(shù)據(jù)類型?復(fù)雜數(shù)據(jù)類型?值類型和引用數(shù)據(jù)類型?堆棧數(shù)據(jù)結(jié)構(gòu)? 基本數(shù)據(jù)類型:Undefined、Nul...
    極樂(lè)君閱讀 5,566評(píng)論 0 106
  • 網(wǎng)上每天充斥著大量對(duì)于胖的負(fù)面言論,什么“一胖毀所有”啦,什么“五月不減肥、六月徒傷悲”啦,輿論的一片倒,讓減肥成...
    牛奶布丁233閱讀 251評(píng)論 3 3
  • 媒體人/陳永英 (在我的懷里,你卻牽起了別人的手,當(dāng)我掏心掏肺真心愛(ài)你的時(shí)候,你虛心假意的和我共享溫柔,其實(shí)你的心...
    chen陳永英閱讀 571評(píng)論 0 0