【问题标题】:jQuery: Any chance to detect from which side the mouse entered a div without the "Offset" Method?jQuery:是否有机会检测到鼠标从哪一侧进入没有“偏移”方法的 div?
【发布时间】:2013-02-07 20:20:12
【问题描述】:

有没有办法检测鼠标光标来自 div 的哪一侧?

目前我正在使用这种方法:

jQuery(this).bind('mousemove',function(e){
    offset_pos_x = parseInt(e.offsetX);
    offset_pos_y = parseInt(e.offsetY);
    ...

然后我寻找鼠标在div内的距离,朝哪个方向。

问题是,这个方法有点麻烦,因为我需要所有 4 个面,而不仅仅是两个,所以我必须检查 offsetX 和 offsetY。

如果我在 div 内移动鼠标,例如 X:+15,Y:-3(以像素为单位),我知道鼠标来自左侧,因为鼠标在 x 轴上移动了 15px,但仅在 -3px y 轴。问题在于,当 X 和 Y 几乎相同时,我不知道鼠标是从左侧还是顶部(例如)。

另外,根据我的另一个问题 (jQuery: mouseenter/mousemove/mouseover not recognized with small div and fast mouse movement),由于浏览器/操作系统的限制,事件不会在 div 一侧的第一个像素上触发。因此,我的“entered_at”坐标不是那么准确 - 示例:

如果我在 div 内(从左至右)快速移动鼠标光标,则“entered_at”坐标位于 x:17,y:76 处。现在,如果我在停止鼠标后将鼠标向左移动,例如移动到 x:6,y:76,则起点和 offsetX 之间的差异为负,因此会触发“光标来自右侧”功能...

还有其他方法可以检测鼠标光标的来源吗?

您好, 帕特里克

【问题讨论】:

    标签: jquery mouseover


    【解决方案1】:

    我不会使用偏移量,而是使用 pageX/pageY(jQuery 标准化这些)。如果光标的第一个 mousemove 事件比任何其他边缘更靠近左边缘,则它来自左侧。您也可以考虑为此使用悬停事件,而不是鼠标移动。

    JSFiddle,由牙买加国旗提供。 http://jsfiddle.net/MJTkk/1/

    function closestEdge(x,y,w,h) {
            var topEdgeDist = distMetric(x,y,w/2,0);
            var bottomEdgeDist = distMetric(x,y,w/2,h);
            var leftEdgeDist = distMetric(x,y,0,h/2);
            var rightEdgeDist = distMetric(x,y,w,h/2);
            var min = Math.min(topEdgeDist,bottomEdgeDist,leftEdgeDist,rightEdgeDist);
            switch (min) {
                case leftEdgeDist:
                    return "left";
                case rightEdgeDist:
                    return "right";
                case topEdgeDist:
                    return "top";
                case bottomEdgeDist:
                    return "bottom";
            }
    }
    
    function distMetric(x,y,x2,y2) {
        var xDiff = x - x2;
        var yDiff = y - y2;
        return (xDiff * xDiff) + (yDiff * yDiff);
    }
    

    【讨论】:

    • 我在使用偏移量之前尝试过pageX/pageY方法,但是(如果我错了请纠正我),使用pageX或offsetX没有区别(我的计算不同但我没有'不认为结果是)
    • 只是为了解释我的意思:我需要一个起点,结束一个终点来计算鼠标移动的方式。但是,如果由于我移动鼠标太快而在 div 中的 +15px(x 轴)上识别了起点,则如果我在将起点向左移动后移动鼠标光标,则终点可能是负数...
    • jQuery 的文档警告使用 offsetX 和 clientX:“.clientX、.offsetX 和 .pageX 等属性是可用的,但对它们的支持因浏览器而异。幸运的是,jQuery 将 .pageX 和 . pageY 属性,以便它们可以在所有浏览器中使用。" api.jquery.com/mousemove
    • 嗯,这比我的版本好得多,然后我错了,pageX/pageY 是检测鼠标移动的更好方法,谢谢!
    • pageX 和 pageY 为您提供相对于图像角落以外的坐标。 jQuery 的 mousemove 文档(上面的链接)解释了差异。
    【解决方案2】:

    这是脚本的正确/工作示例,包括对绝对定位 div 的修复。再次感谢您对 turiyag 的帮助!

    jsfiddle:http://jsfiddle.net/MJTkk/2/

    脚本:

    $(function() {
        $("img").hover(function(e) {
            var el_pos = $(this).offset();
            var edge = closestEdge(e.pageX - el_pos.left, e.pageY - el_pos.top, $(this).width(), $(this).height());
            log('entered at: '+edge);
        }, function(e) {
            var el_pos = $(this).offset();
            var edge = closestEdge(e.pageX - el_pos.left, e.pageY - el_pos.top, $(this).width(), $(this).height());
            log('left at: '+edge+'<br><br>');
        });
    });
    
    function closestEdge(x,y,w,h) {
            var topEdgeDist = distMetric(x,y,w/2,0);
            var bottomEdgeDist = distMetric(x,y,w/2,h);
            var leftEdgeDist = distMetric(x,y,0,h/2);
            var rightEdgeDist = distMetric(x,y,w,h/2);
    
            var min = Math.min(topEdgeDist,bottomEdgeDist,leftEdgeDist,rightEdgeDist);
            switch (min) {
                case leftEdgeDist:
                    return "left";
                case rightEdgeDist:
                    return "right";
                case topEdgeDist:
                    return "top";
                case bottomEdgeDist:
                    return "bottom";
            }
    }
    
    function log(msg) {
        $("#console").append("<pre>" + msg + "</pre>");
    }
    
    function distMetric(x,y,x2,y2) {
        var xDiff = x - x2;
        var yDiff = y - y2;
        return (xDiff * xDiff) + (yDiff * yDiff);
    }
    

    【讨论】:

      【解决方案3】:

      牙买加国旗小提琴中最接近的边缘函数没有达到应有的水平,并且对于某些元素不准确。我们可以使用offsetXoffsetY来简化函数,去掉distMetric函数:

      // Pass object offsetX,offsetY,width,height
      function closestEdge(distLeft,distTop,w,h){
          var distBottom = (h - distTop);
          var distRight = (w - distLeft);
          var min = Math.min(distTop, distBottom, distLeft, distRight);
          switch (min) {
              case distLeft:
                  return "left";
              case distRight:
                  return "right";
              case distTop:
                  return "top";
              case distBottom:
                  return "bottom";
          }
      }
      

      例如:

      $('.btn').on('mouseenter',function(e){
          var edge = closestEdge(e.offsetX, e.offsetY, $(this).width(), $(this).height());
      });
      

      【讨论】:

        【解决方案4】:

        我在使用此代码时遇到了一些问题,在对矩形进行操作时,我发现它会错误地将边缘识别为正确的边缘,而该边缘应该位于顶部。我花了一些时间想出了一个答案,并觉得我会分享:

        var getDir = function( elem, e ) {       
        
                    /** the width and height of the current div **/
                    var w = elem.width();
                    var h = elem.height();
                    var offset = elem.offset();
                    /** calculate the x and y to get an angle to the center of the div from that x and y. **/
                    /** gets the x value relative to the center of the DIV and "normalize" it **/
                    var x = (e.pageX - offset.left - (w/2)) * ( w > h ? (h/w) : 1 );
                    var y = (e.pageY - offset.top  - (h/2)) * ( h > w ? (w/h) : 1 );
        
                    /** the angle and the direction from where the mouse came in/went out clockwise (TRBL=0123);**/
                    /** first calculate the angle of the point, 
                     add 180 deg to get rid of the negative values
                     divide by 90 to get the quadrant
                     add 3 and do a modulo by 4  to shift the quadrants to a proper clockwise TRBL (top/right/bottom/left) **/
                    var direction = Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180 ) / 90 ) + 3 )  % 4;
        
        
                    /** do your animations here **/ 
                    switch(direction) {
                     case 0:
                        return 'top';
                     break;
                     case 1:
                        return 'right';
                     break;
                     case 2:
                           return 'bottom';
                     break;
                     case 3:
                           return 'left';
                     break;
                    }
        
        }
        
        
        $(this).bind('mouseenter',function(e){
            //outputs the direction to the log
            console.log(getDir($(this), e));
        });
        

        信用:jQuery animation for a hover with 'mouse direction'

        【讨论】:

          【解决方案5】:

          这里有一个插件

          https://github.com/JohnnyBeGood34/JQuery-MouseEntrance

          希望能帮到你。

          【讨论】:

            【解决方案6】:

            我使用 jQuery 函数改进了@Patrick 的解决方案,使其拥有更加优雅和强大的自定义 jQuery 函数。

            这里是jQuery getMouseSide jsFiddle

            $(function () {
                $('img').hover(function (event) {
                    log('entered at: ' + $(this).getMouseSide(event))
                }, function (event) {
                    log('left at: ' + $(this).getMouseSide(event) + '<br><br>')
                })
            
                $.fn.getMouseSide = function (event) {
                    function distanceMetric(x, y, x2, y2) {
                        return Math.pow(x - x2, 2) + Math.pow(y - y2, 2)
                    }
            
                    function closestEdge(x, y, w, h) {
                        var edgeDistance = {
                            top:        distanceMetric(x, y, w / 2  , 0)
                            , bottom:   distanceMetric(x, y, w / 2  , h)
                            , left:     distanceMetric(x, y, 0      , h / 2)
                            , right:    distanceMetric(x, y, w      , h / 2)
                        }
                        , edgeDistances = $.map(edgeDistance, function (value) {
                            return [value]
                        })
            
                        return Object.keys(edgeDistance)[
                            $.inArray(
                                Math.min.apply(null, edgeDistances)
                                , edgeDistances
                            )
                        ]
                    }
            
                    var current = $(this)
                    , elementOffset = current.offset()
            
                    return closestEdge(
                        event.pageX - elementOffset.left
                        , event.pageY - elementOffset.top
                        , current.width()
                        , current.height()
                    )
                }
            })
            
            function log(message) {
                $('#console').append('<pre>' + message + '</pre>')
            }
            

            【讨论】:

              猜你喜欢
              • 2017-12-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-11-18
              • 1970-01-01
              • 2015-01-22
              相关资源
              最近更新 更多