美文网首页
菜单栏的切换

菜单栏的切换

作者: 晴天小码农 | 来源:发表于2017-11-30 11:24 被阅读0次

HTML 代码 CSS 省略了。

        <ul>
            <li data-id="a">
                <span>家用电器</span>
            </li>
            <li data-id="b">
                <span>家用电器</span>
            </li>
            <li data-id="c">
                <span>家用电器</span>
            </li>
            
        </ul>

        <div id='sub' class="none">
            <div id='a' class="sub_content ">
                <dl>
                    <dt>
                        <a href="">tv <i>&gt;</i></a>
                    </dt>
                    <dd>
                        <a href="">sdkjfhasdkjfhaskj</a>
                        <a href="">sdkjfhasdkjfhaskj</a>
                        <a href="">sdkjfhasdkjfhaskj</a>
                        <a href="">sdkjfhasdkjfhaskj</a>
                    </dd>
                </dl>
            </div>
            <div id='b' class="sub_content ">
                <dl>
                    <dt>
                        <a href="">tv <i>&gt;</i></a>
                    </dt>
                    <dd>
                        <a href="">sAAAAAAAAAAAAkjfhaskj</a>
                        <a href="">sdkjfhasdkjfhaskj</a>
                        <a href="">sdkjfhasdkjfhaskj</a>
                        <a href="">sdkjfhasdkjfhaskj</a>
                    </dd>
                </dl>
            </div>
            <div id='c' class="sub_content">
                <dl>
                    <dt>
                        <a href="">tv <i>&gt;</i></a>
                    </dt>
                    <dd>
                        <a href="">sdkBBBBBBBBBBBBBBaskj</a>
                        <a href="">sdkjfhasdkjfhaskj</a>
                        <a href="">sdkjfhasdkjfhaskj</a>
                        <a href="">sdkjfhasdkjfhaskj</a>
                    </dd>
                </dl>
            </div>
        </div>
    </div>

JS 代码 使用Jquery 利用mousetern mouseout时间 事件委托

$( () => {
$(() => {
    // 子菜单
    let sub = $('#sub');
    // 主菜单选中
    let activeRow;
    // 子菜单选中
    let activeMenu;
    // 保存定时器
    let timer;

    // 预测用户是不是想移入二级菜单  li标签到菜单的上边缘 和 下边缘组成一个三角形,利用向量判断是不是绘制了一个三角形

    // 追踪鼠标的 位置 只需要三个值

    let mouseTrack = []

    // 把鼠标绑定的事件绑定在document上

    mouseHandler = (e) => {

        mouseTrack.push({

            x: e.pageX,
            y: e.pageY
        })

        // 只保存三个值 大于三个值 去掉第一个值
        if (mouseTrack.length > 3) {

            mouseTrack.shift();
        }

    }


    $('#test')
        .on("mouseenter", () => {

            sub.removeClass('none');

            $(document).bind("mousemove", mouseHandler)
        })
        .on("mouseleave", () => {

            sub.addClass('none');

            // 鼠标移动事件的解绑

            $(document).unbind("mousemove", mouseHandler);
        })
        // 事件委托
        .on('mouseenter', 'li', (e) => {

            // 当鼠标从一个li到另一个li menu会马上跟着变化 用户就无法点击 利用定时器

            if (timer) {

                clearTimeout(timer);
            }

            // 第一次鼠标移入
            if (!activeRow) {

                activeRow = $(e.target).addClass('active');

                activeMenu = $("#" + activeRow.data("id"));

                activeMenu.removeClass("none");
            }

            let currenMouse = mouseTrack[2];
            // 上一次的鼠标位置
            let leftCorner = mouseTrack[1];

            let delay = needDealy(sub,leftCorner,currenMouse) ;
            // 如果用户准备移入对应的子菜单
            if(delay) {

                timer = setTimeout(() => {
    
                    // 鼠标移入另外一个li
                    activeRow.removeClass('active');
    
                    activeMenu.addClass('none');
    
                    //  重新指向选中的li
    
                    activeRow = $(e.target);
    
                    activeMenu = $("#" + activeRow.data("id"));
    
                    activeRow.addClass("active");
    
                    activeMenu.removeClass("none");
    
                    timer = null;
                }, 300);
            }else{

                var perActiveRow = activeRow;

                var perActiveMenu = activeMenu;

                activeRow = $(e.target);

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

                perActiveRow.removeClass('active');

                perActiveMenu.addClass('none');

                activeRow.addClass('active');

                activeMenu.removeClass('none')
            }



        });

    // 判断用户鼠标是否准备移入当前选中的li对应的menu 判断当前鼠标位置是否在 与当面位置上一次的位置 与菜单的左上角和左下角组成的三角形中 利用三个向量乘积是否大于0

    // 向量计算的工具函数
    // 计算2个坐标点的构成向量
    function vector(a, b) {

        return {
            x: a.x - b.x,
            y: a.y - b.y
        }
    }
    // 向量乘积
    function vectorProduct(a, b) {

        return a.x * b.y - a.y * b.x;
    }

    // 判断是否在三角形内

    function isPositionInAngle(p, a, b, c) {

        let pa = vector(p, a);
        let pb = vector(p, b);
        let pc = vector(p, c);

        let t1 = vectorProduct(pa, pb);
        let t2 = vectorProduct(pa, pc);
        let t3 = vectorProduct(pb, pc);

        return t1 * t2 * t3 > 0;
        // 如果大于0 表示在三角形内
    }

    // 判断用户是否会移入当选选中li 对应的子菜单

    // ele 菜单 leftCorner 鼠标上一次的位置 currenMouse鼠标当前位置
    function needDealy(ele, leftCorner, currenMouse) {

        // 菜单的位置
        let offset = ele.offset();
        // 菜单左上角的位置
        let topLeft = {

            x: offset.left,
            y: offset.top
        }
        // 菜单左下角那个点的位置
        let bottomLeft = {

            x: offset.left,
            y: offset.top + ele.height
        }


        return isPositionInAngle(currenMouse,leftCorner,topLeft,bottomLeft) ;
    }

})

这样子就可以做出完美的菜单栏无延迟的切换了.
知识点 事件委托 提前判断用户行为

相关文章

网友评论

      本文标题:菜单栏的切换

      本文链接:https://www.haomeiwen.com/subject/gxambxtx.html