问答详情
源自:4-2 基于用户行为预测的切换技术

当鼠标指向div,但并没有指向li时,为什么会出现这种白框?

当鼠标指向div,但并没有指向li时,为什么会出现这种白框?http://img.mukewang.com/597af91a0001e0d309250108.jpg

js代码:

/** Created by sofiaZ on 17/7/22.*/
$(document).ready(function(){     //ready事件,当DOM加载完毕且页面完全加载时发生。把所有jjQuery事件和函数置于该事件比较好。
    var sub =$('#sub');//申明一个变量指向子菜单,这是直接转成

    var activeRow;      //申明一个变量,指向当前激活的以及菜单的行
    var activeMenu;    //二级菜单
                       //没赋初值时为false
  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({     //push()方法向数组的末尾添加一个或多个元素,返回值为新数组的长度
            x: e.pageX,
            y: e.pageY      //鼠标指针的位置,x相对于文档左边缘,y相对于文档上边缘
        });
        if (mouseTrack.length > 3) {
            mouseTrack.shift();     //shift事件把数组的第一个元素删除,返回第一个元素的值。这里只想要当前以及上一次的坐标,因此保留三个就够了
        }

    };

    $('#test')
        .on('mouseenter',function(e) {   //on事件,向元素添加事件处理程序
            sub.removeClass('none');   //鼠标移动到元素时,出现二级菜单
            $(document).bind('mousemove', moveHandler);
        }
    )
            //document对象对应整个html文档,$(document)是对document的jquery操作,bind为元素添加事件(mousemove常绑定在document事件上)
        .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);    //当鼠标离开菜单栏时,对mousemove事件进行解绑,以免影响页面其他事件
        })
        .on('mouseenter','li',function(e){
            if (!activeRow){
                activeRow = $(e.target);
                activeRow.addClass('active');
                activeMenu = $('#' + activeRow.data('id'));
                activeMenu.removeClass('none');
                return;
            }

            if (timer) {

                clearTimeout(timer);
            }    //当事件还没触发时,清掉计时器,这样可以保证事件只触发最后一次的?(debounce去抖技术基本原理?)

            var currMousePos = mouseTrack[mouseTrack.length - 1];   //当前鼠标坐标
            var leftCorner = mouseTrack[mouseTrack.length - 2];    //上一次鼠标坐标

            var delay = needDelay(sub, leftCorner, currMousePos);

            if (delay) {

                timer = setTimeout(function(){     //setTimeout返回值是一个ID?
                if (mouseInsub) {
                    return;
                }

                activeRow.removeClass('active');
                activeMenu.addClass('none');

                activeRow = $(e.target);
                activeRow.addClass('active');
                activeMenu = $('#' + activeRow.data('id'));
                activeMenu.removeClass('none');          //大概就是,移到下一个li时,跳过if,重新获取target与id??
                timer = null;       //这样的话,返回什么呢??                   // 因为active是全局变量????

            },300);     //300毫秒后执行,这样当鼠标从一级菜单转换到二级菜单时,中间划过其他li也不会触动其对应的二级菜单,因为有延迟

            }

            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')


            }

            })
});

函数的js代码:

/**
 * Created by sofiaZ on 17/7/27.
 */
function sameSign(a, b) {
    return(a ^ b) >=0;     //a^b为a按位异或b,若结果为正(最高位为0),则a和b要么同正要么同负)
}

function vector(a,b){
    return{
        x: b.x- a.x,
        y: b.y- a.x

    }
}
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 + elem.height()
    };

    return isPointInTrangle(currMousePos, leftCorner, topLeft, bottomLeft)


提问者:辰辰的宝宝 2017-07-28 16:55

个回答

  • ZLW012494
    2018-07-13 14:11:40

    不用这样,只要把边距去掉在 li  加点边缘就行 就解决了

  • Hou_
    2017-08-08 14:12:59

    因为你第32行是以主菜单(#test)绑定事件的 而主菜单有一个上边缘和一个下边缘 当你移到这个上边缘或者下边缘却没移到 li 元素上时  二级菜单sub显示了 但是二级菜单里面的元素却依然处于display:none状态

    你可以将32行改为('#test li')绑定到 li元素上 同时修改55行为.on('mouseenter',function(e)就可以了

    不过我也遇到过问题 就是没修改之前 我设置setTimeOut 能正常运行 但是我修改后 就失效了 不知道有没有人知道是什么原因


  • 一时_
    2017-08-01 21:47:16

    应该是 #sub的div样式中的padding的问题。

  • 有星小冰_0
    2017-08-01 17:28:14

    应该是id=sub的div吧,看看样式