京东无延迟菜单实现

一、分析

segmentfault.com/a/119000001…

二、慕课网视频分析原理

https:/www.imooc.com/qadetail/247033

三、源码

<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
    <meta charset="UTF-8">
    <title>京东首页商城菜单导航</title>
    <style>
        .wrap {
            position: relative;
            width: 200px;
            left: 50px;
            top: 50px;
            background: #6c6669;
            padding: 15px 0;
        }

        .wrap ul {
            list-style: none;
            margin: 0;
            padding: 0;
            color: #ffffff;
            border-right-width: 0;
        }

        .wrap ul li {
            position: relative;
            height: 40px;
            line-height: 40px;
            padding-left: 12px;
            cursor: pointer;
            font-size: 14px;

        }

        .wrap ul li.active {
            background: #999395;
        }

        .wrap ul li span:hover {
            color: #c81623;
        }

        .none {
            display: none;
        }

        .sub {
            width: 600px;
            min-height: 270px;
            position: absolute;
            border: 1px solid #f7f7f7;
            background: #f7f7f7;
            left: 200px;
            top: 0;

        }

        .sub_content a {
            text-decoration: none;
            color: #666;
            font-size: 12px;
        }

        .sub_content dl {
            overflow: hidden;
        }

        .sub_content dt {
            float: left;
            width: 120px;
            clear: left;
            font-weight: bold;
            position: relative;
            text-align: center;
        }

        .sub_content dd {
            margin-left: 5px;
            border-top: 1px solid #eee;
            margin-bottom: 5px;
        }

        .sub_content dd a {
            border-left: 1px solid #e0e0e0;
            padding: 0 10px;
            margin: 4px 0;
        }
    </style>
</head>
<body>
<div id="wrap" class="wrap">
    <!--左侧菜单-->
    <ul>
        <li class="menu-item" data-id="a">
            <span>一级导航</span></li>
        <li class="menu-item" data-id="b"><span>二级导航</span></li>
        <li class="menu-item" data-id="c"><span>二级导航</span></li>
    </ul>

    <!--右侧菜单-->
    <div id="sub" class="sub none">
        <div id="a" class="sub_content">
            <dl>
                <dt>
                    <a href="#">二级菜单名称1</a>
                </dt>
                <dd>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">二级菜单名称1</a>
                </dt>
                <dd>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">二级菜单名称1</a>
                </dt>
                <dd>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">二级菜单名称1</a>
                </dt>
                <dd>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">二级菜单名称1</a>
                </dt>
                <dd>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">二级菜单名称1</a>
                </dt>
                <dd>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                </dd>
            </dl>
            <dl>
                <dt>
                    <a href="#">二级菜单名称1</a>
                </dt>
                <dd>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                </dd>
            </dl>
        </div>
        <div id="b" class="sub_content none">
            <dl>
                <dt>
                    <a href="#">二级菜单名称2</a>
                </dt>
                <dd>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                </dd>
            </dl>
        </div>
        <div id="c" class="sub_content none">
            <dl>
                <dt>
                    <a href="#">二级菜单名称3</a>
                </dt>
                <dd>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                    <a href="#"> 三级菜单 </a>
                </dd>
            </dl>
        </div>
    </div>
</div>
<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script>
    var $wrap = $("#wrap");
    var $sub = $("#sub");

    // 定制定时器
    var timer;
    // 把之前前滑动的值保存
    var menuDom;
    var subDom;

    // 鼠标是否在子菜单里
    var mouseInSub = false;
    // 记录鼠标的位置
    var mouseTrack = [];

    $sub.on("mouseenter", function () {
        mouseInSub = true;
    });
    $sub.on("mouseleave", function () {
        mouseInSub = false;
    });


    $wrap.on("mouseenter", function () {
        $(document).bind("mousemove", moveHandler);// 用于记录鼠标位置
    })

    $wrap.on("mouseenter", ".menu-item", function () {
        var _this = this;
        // 子菜单打开
        $sub.removeClass("none");


        // 第一次就添加样式
        if (!menuDom) {
            resetClass(_this);
            return
        }

        if (timer) {
            clearTimeout(timer);
        }
        var curMouse = mouseTrack[mouseTrack.length - 1]; // 鼠标当前坐标
        var prevMouse = mouseTrack[mouseTrack.length - 2]; // 鼠标上一次坐标
        var delay = needDelay($sub, curMouse, prevMouse);  // 是否在固定三角形内
        // 加入延迟器,解决斜方移动切换,只能折线移动的问题
        if (delay) {
            // 延迟子菜单消失
            timer = setTimeout(function () {
                if (mouseInSub) {
                    return;
                }

                resetClass(_this)
                timer = null;
            }, 300)
        } else {
            // 子菜单快速消失
            resetClass(this)
        }


    });


    // 鼠标离开
    $wrap.on("mouseleave", function () {
        //
        $sub.addClass("none")
        if (menuDom) {
            menuDom.removeClass("active");
            menuDom = null;
        }
        if (subDom) {
            subDom.addClass("none");
            subDom = null;
        }

        $(document).off("mousemove", moveHandler); // 注意解绑,以免影响其他组件
    });


    // 重置class
    function resetClass(cur) {
        if (menuDom) {
            // 消除之前的样式
            menuDom.removeClass("active");
            subDom.addClass("none");
        }

        // 当前鼠标位置加上样式
        var id = $(cur).data("id");
        menuDom = $(cur);
        subDom = $("#" + id)
        menuDom.addClass("active");
        subDom.removeClass("none");
    }

    /**
     * 计算2个向量的向量坐标
     * @param a 向量a
     * @param b 向量b
     */
    function vector(a, b) {
        return {
            x: (b.x - a.x),
            y: (b.y - a.y)
        }
    }

    // 获取鼠标经过主菜单的坐标
    function moveHandler(e) {
        mouseTrack.push({
            x: e.pageX,
            y: e.pageY
        });

        // 只需要当前点和上一个点 ,只需要保存最近2个点
        if (mouseTrack.length > 3) {
            mouseTrack.shift();
        }
    };

    // 向量的叉乘
    function vectorPro(a, b) {
        return (a.x * b.y) - (a.y * b.x);
    }

    // 用位运算高效判断符号相同
    function sameSign(n1, n2) {
        return (n1 ^ n2) >= 0;
    }

    // 判断点是否在三角形内
    function isPointInTranjgle(p, a, b, c) {
        var pa = vector(p, a);
        var pb = vector(p, b);
        var pc = vector(p, c);

        var t1 = vectorPro(pa, pb);
        var t2 = vectorPro(pb, pc);
        var t3 = vectorPro(pc, pa);

        return sameSign(t1, t2) && sameSign(t2, t3);
    }

    // 是否需要延迟
    function needDelay(ele, curMouse, prevMouse) {
        if (!curMouse || !prevMouse) {
            return;
        }
        var offset = ele.offset();

        // 左上点
        var topleft = {
            x: offset.left,
            y: offset.top
        };
        // 左下点
        var leftbottom = {
            x: offset.left,
            y: offset.top + ele.height()
        };

        return isPointInTranjgle(curMouse, prevMouse, topleft, leftbottom);
    }
</script>
</body>
</html>
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值