课程代码——20170503
如果鼠标移出菜单栏,然后再进去时,显示就会不正确了,是不是因为var leftCorner=mouseTrack[mouseTrack.length-2];计算会出错。
代码如下:
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script> //二进制的正负表示是在最高位,1表示负,0表示正,抑或运算是仅当对应的2位有一位为1时才返回1,反过来如果抑或运算返回的结果是0(正),则一定是2个1,或者2个0.反之,则是一个0,一个1 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 } //叉乘判断方法 function isPointInTrangle(p,a,b,c){//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){//用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(currMousePos,leftCorner,topLeft,bottomLeft) } </script> <script> $(function(){ var sub=$('#sub'); var activeRow;//选中的行 var activeMenu;//选中的行对应的二级菜单 var timer;//setTimeout返回的计时器id var mouseInSub=false;//当前鼠标是否在子菜单里 sub.on('mouseenter',function(e){ mouseInSub=true; }).on('mouseleave',function(e){ mouseInSub=false; }); //创建数组,记录 var mouseTrack=[];//数组跟踪记录鼠标的位置 var moveHandler=function(e){//鼠标离开菜单时,需要对绑定在document上的mousemove事件解绑,以免影响页面中其他组件,所以将事件监听函数独立出来,方便后续解绑操作 mouseTrack.push({ x:e.pageX, y:e.pageY }); if(mouseTrack.length>3){ mouseTrack.shift(); } }; $('#test') .on('mouseenter',function(e){ //sub.removeClass('none'); $(document).bind('mousemove',moveHandler);//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('mouseove',moveHandler); }) .on('mouseenter','li',function(e){//一级菜单的列表项绑定事件 sub.removeClass('none');//鼠标移动到一级菜单时,二级菜单显示 if(!activeRow){//移过去没有激活的一级菜单 activeRow=$(e.target); activeRow.addClass('active'); activeMenu=$('#'+activeRow.data('id')); activeMenu.removeClass('none'); return; } //debounce:mouseenter频繁触发时,只执行最后一次 if(timer){ clearTimeout(timer); } console.log(mouseTrack) 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 prevActiveRow=activeRow; var prevActiveMenu=activeMenu; activeRow=$(e.target); activeMenu=$('#'+activeRow.data('id')); prevActiveRow.removeClass('active'); prevActiveMenu.addClass('none');//上一次二级菜单隐藏 activeRow.addClass('active'); activeMenu.removeClass('none');//上一次二级菜单显示 } }); }); </script>