判断鼠标进入或离开容器的方向

  最近准备找工作,在拉勾网上瞅了瞅,无意中发现了下图的效果,这不由得引起了我的思考。是怎么判断鼠标从哪个方位进入或离开容器的呢,脑袋里不由自主的出现了n多个if else。后来在网上找了一番,原来有一个很牛逼的算法。

jdfw.gif


算法如下:

$(".wrap").bind("mouseenter", function(e) {
  var w = $(this).width(), 
      h = $(this).height(), 
      x = (e.pageX - this.offsetLeft - (w / 2)) * (w > h ? (h / w) : 1), 
      y = (e.pageY - this.offsetTop - (h / 2)) * (h > w ? (w / h) : 1),
     direction = Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180) / 90) + 3) % 4;
     alert(direction);  //direction的值为“0,1,2,3”分别对应着“上,右,下,左”
}

当我看到这个算法时愣了一下,第6行完全不懂,于是又在网上遨游了一番,找到一篇对这个算法分析的文章,才知道是根据鼠标进入或离开容器时的点的atan2(y,x)值所在数轴的象限来映射容器四条边框。详情请点击这里


鼠标进入或离开容器时,我们可以得到direction,值为0,1,2,3,分别对应上,右,下,左。那么接下来就好办了。我们只需根据direction的值来确定遮罩层绝对定位的left和top值,代码如下:

HTML:

<ul class="wrap">
  <li><div></div></li>
  <li><div></div></li>
  <li><div></div></li>
  <li><div></div></li>
  <li><div></div></li>
</ul>


CSS:

.wrap li{
  width:150px;
  height:150px;
  background:#33aa00;
  display:inline-block;
  position:relative;
  overflow: hidden;
} 
.wrap li div{
  margin-right:10px;
  width:100%;
  height:100%;
  left:-100%;
  background:blue;
  display: inline-block;
  position:absolute;
}


javascript(基于jquery):

首先,声明一个函数,通过direction的值确定遮罩层定位的css样式

function getStyle(direction){
var b,c,
     top = {left: "0px",top: "-100%"}, 
     bottom = {left: "0px",top: "100%"}, 
     left = {left: "-100%",top: "0px"}, 
     right = {left: "100%",top: "0px"}, 
     t = {top: "0px"}, l = {left: "0px"};
switch (direction) {
    case 0:
      b = top, c = t;  //从上面到中间
        break;
    case 1:
      b = right, c = l;  //从右边到中间
        break;
    case 2:
      b = bottom, c = t; //从下面到中间
        break;
    case 3:
      b = left, c = l  //从左边到中间
}
return {from: b,to: c}
}


然后绑定容器li的mouseenter mouseleave事件

$(".wrap li").bind("mouseenter mouseleave", function(e) {
  var childDiv = $(this).find("div"),
        w = $(this).width(), 
        h = $(this).height(), 
        x = (e.pageX - this.offsetLeft - (w / 2)) * (w > h ? (h / w) : 1), 
        y = (e.pageY - this.offsetTop - (h / 2)) * (h > w ? (w / h) : 1),
        direction = Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180) / 90) + 3) % 4,
        cssStyle = null;
  if(e.type == 'mouseenter'){
        //鼠标进入容器
    
        //根据鼠标进入容器时的方位确定遮罩层定位的css样式 
        cssStyle = getStyle(direction);
        
        //设置遮罩层进入时的位置
        childDiv.hide().css(cssStyle.from);
        childDiv.show(0,function(){
        childDiv.css("transition","all 0.3s ease");
        
        //更改遮罩层的位置
        childDiv.css(cssStyle.to);
    });
  }else{
        //鼠标离开容器
    
        //根据鼠标离开的方位确定遮罩层定位的css样式
        cssStyle = getStyle(direction);
        
        //由于鼠标是从容器中移动至四周,此时的遮罩的最终定位的样式应该是cssStyle.from
        childDiv.css(cssStyle.from);
    } 
});

实现方法大概就这样,当然代码仍然可以进行优化。查看demo请点击这里