无延迟菜单 JQuery

1、实现分类导航菜单的基本布局结构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="jquery-3.3.1.js"></script>
    <style>
        .wrap{
            position: relative;/*为了使菜单是相对于这个div容器定位的而不是相对于body*/
            width: 200px;
            left: 50px;
            top:50px;
        }
        ul{
            padding: 15px 0;
            margin:9;
            list-style: none;
            background-color: #CC33FF;
            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来配合的时候就添加类,因为Js可以很方便的添加或移动类,如果不需要的话就用Hover来控制*/
        li.active{
            background-color: #FFFF66;
        }
        li span:hover{
            color: coral;
        }
        .none{
            display: none;
        }
        #sub{
            width: 600px;
            position: absolute;
            border: 1px solid #f7f7f7;
            background: #f7f7f7;
            box-shadow:2px 0 5px  #99CC33;/*加阴影*/
            left:200px;
            top: 0;
            box-sizing: border-box;/*您需要并排放置两个带边框的框,可通过将 box-sizing 设置为 "border-box"。这可令浏览器呈现出带有指定宽度和高度的框,并把边框和内边距放入框中。盒模型采用Border-box*/
            margin: 0;
            padding: 10px;

        }
        .sub_content a{
            font-size: 12px;
            color: #0000CC;
            text-decoration: none;/*去掉下划线*/
            border-left: 1px solid #99CC33;
            padding: 0 10px;
            margin: 4px 0;
        }
        .sub_content dl{
            /*因为DL中间会有浮动元素,所以加入overflow:hidden来触发bfc令他可以被浮动元素撑开而不是失去自己的高度*/
            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;/*分号前面代表font-size  分好后面代表line-height*/
            position: absolute;
            right: 5px;
            top:5px;
        }
    </style>
</head>
<body>
<!--承载菜单-->
<div class="wrap">
    <!--用无序列表实现一级菜单-->
    <ul>
        <!--加入id用来与二级菜单进行区分-->
        <li data-id="a">
            <span>一</span>
        </li>
        <li data-id="b">
            <span>二 / 三 / 四</span>
        </li>
        <li data-id="c">
            <span>五 / 六 / 七</span>
        </li>
        <li data-id="d">
            <span>八 / 九 / 十</span>
        </li>
        <li data-id="e">
            <span>十一 / 十二 / 十三</span>
        </li>
        <li data-id="f">
            <span>十四 / 十五 / 十六</span>
        </li>
        <li data-id="g">
            <span>十七 / 十八 / 十九</span>
        </li>
        <li data-id="h">
            <span>二十 / 二一 / 二二</span>
        </li>
    </ul>
    <div id="sub" class="">
        <!--二级菜单的id与一级菜单的id一一对应 方便用DataSet来控制-->
        <div id="a" class="sub_content ">
            <dl>
            <!--在HTML里面不能直接写箭头,因为会跟元素标签的箭头混了,用这种方式<i>&gt;</i>-->
            <dt><!--标题-->
                <a href="#">1<i>&gt;</i></a>
            </dt>
            <dd><!--子内容-->
                <a href="#">1.1</a>
                <a href="#">1.2</a>
                <a href="#">1.3</a>
            </dd>
            </dl>
            <dl>
                <!--在HTML里面不能直接写箭头,因为会跟元素标签的箭头混了,用这种方式<i>&gt;</i>-->
                <dt><!--标题-->
                    <a href="#">2<i>&gt;</i></a>
                </dt>
                <dd><!--子内容-->
                    <a href="#">2.1</a>
                    <a href="#">2.2</a>
                    <a href="#">2.3</a>
                </dd>
            </dl>
            <dl>
                <!--在HTML里面不能直接写箭头,因为会跟元素标签的箭头混了,用这种方式<i>&gt;</i>-->
                <dt><!--标题-->
                    <a href="#">3<i>&gt;</i></a>
                </dt>
                <dd><!--子内容-->
                    <a href="#">3.1</a>
                    <a href="#">3.2</a>
                    <a href="#">3.3</a>
                </dd>
            </dl>
            <dl>
                <!--在HTML里面不能直接写箭头,因为会跟元素标签的箭头混了,用这种方式<i>&gt;</i>-->
                <dt><!--标题-->
                    <a href="#">4<i>&gt;</i></a>
                </dt>
                <dd><!--子内容-->
                    <a href="#">4.1</a>
                    <a href="#">4.2</a>
                    <a href="#">4.3</a>
                </dd>
            </dl>
            <dl>
                <!--在HTML里面不能直接写箭头,因为会跟元素标签的箭头混了,用这种方式<i>&gt;</i>-->
                <dt><!--标题-->
                    <a href="#">5<i>&gt;</i></a>
                </dt>
                <dd><!--子内容-->
                    <a href="#">5.1</a>
                    <a href="#">5.2</a>
                    <a href="#">5.3</a>
                </dd>
            </dl>
            <dl>
                <!--在HTML里面不能直接写箭头,因为会跟元素标签的箭头混了,用这种方式<i>&gt;</i>-->
                <dt><!--标题-->
                    <a href="#">6<i>&gt;</i></a>
                </dt>
                <dd><!--子内容-->
                    <a href="#">6.1</a>
                    <a href="#">6.2</a>
                    <a href="#">6.3</a>
                </dd>
            </dl>
            <dl>
                <!--在HTML里面不能直接写箭头,因为会跟元素标签的箭头混了,用这种方式<i>&gt;</i>-->
                <dt><!--标题-->
                    <a href="#">7<i>&gt;</i></a>
                </dt>
                <dd><!--子内容-->
                    <a href="#">7.1</a>
                    <a href="#">7.2</a>
                    <a href="#">7.3</a>
                </dd>
            </dl>
            <dl>
                <!--在HTML里面不能直接写箭头,因为会跟元素标签的箭头混了,用这种方式<i>&gt;</i>-->
                <dt><!--标题-->
                    <a href="#">8<i>&gt;</i></a>
                </dt>
                <dd><!--子内容-->
                    <a href="#">8.1</a>
                    <a href="#">8.2</a>
                    <a href="#">8.3</a>
                </dd>
            </dl>
        </div>
    </div>
</div>
</body>
</html>

2、开发普通二级菜单
2.1、事件代理方式进行绑定
2.2、mouseenter和mouseover的区别
使用mouseover/mouseout时,如果鼠标移动到子元素上,即便没有离开父元素,也会触发父元素的mouseout事件;
使用mouseenter/mouseleave时,如果鼠标没有离开父元素,在其子元素上任意移动,也不会触发mouseleave事件

$(document).ready(function(){
    var sub = $("#sub");
    var activeRow;
    var activeMenu;

    $("#test").on('mouseenter',function (e) {
        sub.removeClass('none')
    }).on('mouseleave',function(e){
        sub.addClass('none');
        /*当鼠标离开一级菜单容器的时候,如果存在激活的行,要把样式去掉*/
        if(activeRow){
            activeRow.removeClass('active')
            activeRow=null;
        }
        if(activeMenu){
            activeMenu.addClass('none')
            activeMenu = null;
        }
    })
    //对一级菜单中的每一个列表项绑定事件,采用事件代理的方式进行绑定 并不是利用循环
        .on('mouseenter','li',function (e) {
             //当前移动过去的时候并没有激活的列表项
            if(!activeRow){
                activeRow=$(e.target).addClass('active')
                activeMenu = $('#'+ activeRow.data('id'))
                activeMenu.removeClass('none')
                return;
            }
            activeRow.removeClass()
        })
});

利用延迟和去抖技术进行优化
1、切换子菜单的时候用SetTimeout设置延迟
2、debounce(js里面常用)去抖技术,在事件被频繁触发时,只进行一次处理

   if (timer){
                clearTimeout(timer)
            }
            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)

3、基于用户行为预测的切换技术
新增function.js

function sameSign(a,b) {
    //二进制的政府表示在最高位,1标识负,0标识整  儿异或运算只有两个都为0时才是0
    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(pa,pc)

    //使用位运算的技巧来判断是否符号一致
    return sameSign(t1,t2) && sameSign(t2,t3)
}
//写一个函数来判断是否需要延迟
function needDelay(elem,leftCorner,currMousrPos) {
    //利用jQuery的offset方法获取鼠标所在位置的上下边缘坐标
    var offset =elem.offset();

    var topLeft = {
        x:offset.left,
        y:offset.top
    }
    var bottomLeft = {
        x:offset.left,
        y:offset.top + elem.height()
    }
    return isPointinTrangle(currMousrPos,leftCorner,topLeft,bottomLeft)

}

TabTest.js修改

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
                    }
                    activeRow.removeClass('active');
                    activeMenu.addClass('none');

                    activeRow = $(e.target);
                    activeRow.addClass('active');
                    activeMenu = $('#'+activeRow.data('id'))
                    activeMenu.removeClass('none')
                    timer=null
                },300)
            }else{
                //如果不在三角形内直接进行菜单的切换
                var preveActiveRow = activeRow;
                var preveActiveMenu = activeMenu;

                activeRow = $(e.target)
                activeMenu = $('#'+activeRow.data('id'))

                preveActiveRow.removeClass('active');
                preveActiveMenu.addClass('none');

                activeRow.addClass('active')
                activeMenu.removeClass('none');
            }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值