【问题标题】:How to start mouseover event while dragging如何在拖动时启动鼠标悬停事件
【发布时间】:2012-01-26 16:43:00
【问题描述】:

当我将一个元素拖到另一个有鼠标悬停事件的div 上时,该事件不会触发。但是,如果我将鼠标悬停在它上面而不拖动,它就可以工作。

如果我将另一个元素拖到元素上,有没有办法检测悬停事件?

【问题讨论】:

  • 你在使用 jQuery UI 吗?
  • 不,我正在使用自定义创建的拖动
  • 查看该代码会有所帮助。将其放入问题中或将其粘贴到jsfiddle
  • 如果您将鼠标悬停在被另一个元素覆盖的元素上,则不会触发 mouseover 事件(除非覆盖元素是该元素的子元素,在这种情况下它会冒泡)。恐怕你将不得不通过 X 和 Y 位置来做任何你想做的事情。
  • X 和 Y 坐标是非常繁琐的工作,而且很容易出错。只需将拖动的元素放在光标旁边,这样它就不会阻止鼠标与其后面的元素交互。

标签: javascript jquery hover draggable


【解决方案1】:

这里是一个使用 X-Y 坐标解的例子。

Working example on jsfiddle

这个例子可以改进,但是是一个很好的起点。

只需跟踪鼠标位置并检查它是否出现在可放置对象的任何边界框内。因此,如果 mouseup 事件在其中任何一个上触发,则拖放对象。

您还可以使用您正在拖动的对象的坐标来检测它是否在可放置框上,但它需要更多代码来查找边界框坐标并且使用鼠标对我来说就足够了。

代码使用 jQuery,但没有使用 jQueryUI。 我在 Chrome、Firefox 和 Opera 中测试过,但不是 IE :)

如果无法访问 jsfiddle,我也会在此处添加代码。

HTML

<p>Drag orange boxes to grey ones</p>
<div class="droppable"></div>
<div class="droppable"></div>
<div class="droppable"></div>
<div class="droppable"></div>

<div class="draggable"></div>
<div class="draggable"></div>
<div class="draggable"></div>

CSS

.droppable {
    width:50px;
    height:50px;
    float: left;
    background-color: #DDD;
    margin: 5px;
}

.draggable {
    width:40px;
    height:40px;
    float: right;
    background-color: #FC0;
    margin: 5px;
    cursor: pointer;
}

.dropped {
    background-color: #FC0;
}

.somethingover {
    background-color: #FCD;
}

JS

var dragged, mousex, mousey, coordinates = [];

var continueDragging = function(e) {
    // Change the location of the draggable object
    dragged.css({
        "left": e.pageX - (dragged.width() / 2),
        "top": e.pageY - (dragged.height() / 2)
    });

    // Check if we hit any boxes
    for (var i in coordinates) {
        if (mousex >= coordinates[i].left && mousex <= coordinates[i].right) {
            if (mousey >= coordinates[i].top && mousey <= coordinates[i].bottom) {
                // Yes, the mouse is on a droppable area
                // Lets change the background color
                coordinates[i].dom.addClass("somethingover");
            }
        } else {
            // Nope, we did not hit any objects yet
            coordinates[i].dom.removeClass("somethingover");
        }
    }

    // Keep the last positions of the mouse coord.s
    mousex = e.pageX;
    mousey = e.pageY;
}

var endDragging = function(e) {
    // Remove document event listeners
    $(document).unbind("mousemove", continueDragging);
    $(document).unbind("mouseup", endDragging);

    // Check if we hit any boxes
    for (var i in coordinates) {
        if (mousex >= coordinates[i].left && mousex <= coordinates[i].right) {
            if (mousey >= coordinates[i].top && mousey <= coordinates[i].bottom) {
                // Yes, the mouse is on a droppable area
                droptarget = coordinates[i].dom;
                droptarget.removeClass("somethingover").addClass("dropped");
                dragged.hide("fast", function() {
                    $(this).remove();
                });
            }
        }
    }

    // Reset variables
    mousex = 0;
    mousey = 0;
    dragged = null;
    coordinates = [];
}

var startDragging = function(e) {
    // Find coordinates of the droppable bounding boxes
    $(".droppable").each(function() {
        var lefttop = $(this).offset();
        // and save them in a container for later access
        coordinates.push({
            dom: $(this),
            left: lefttop.left,
            top: lefttop.top,
            right: lefttop.left + $(this).width(),
            bottom: lefttop.top + $(this).height()
        });
    });

    // When the mouse down event is received
    if (e.type == "mousedown") {
        dragged = $(this);
        // Change the position of the draggable
        dragged.css({
            "left": e.pageX - (dragged.width() / 2),
            "top": e.pageY - (dragged.height() / 2),
            "position": "absolute"
        });
        // Bind the events for dragging and stopping
        $(document).bind("mousemove", continueDragging);
        $(document).bind("mouseup", endDragging);
    }
}

// Start the dragging
$(".draggable").bind("mousedown", startDragging);

【讨论】:

  • 一开始我有点怀疑,但这项技术对我来说效果很好 - 非常感谢!
【解决方案2】:

在所有提供的答案中,我没有看到最简单和最明显的答案(也许我在 OP 问题中遗漏了一些东西)。但是,如果后来有人偶然发现了这个,并且需要在纯 JS 中快速简单的解决方案..

你可以通过改变元素类名ondragover,然后改回原来的类ondragleave

my_element.ondragover = function(ev) {  
 ev.preventDefault();  
 this.className = 'myElem_dragover';  
}  
my_element.ondragleave = function(ev) {  
 ev.preventDefault();  
 this.className = 'myElem_orig';  
}

CSS

.myElem_orig {     //this is your initial class for element
  top: 30px;
  left: 20px;
  .....
  background-color: blue;  
}  

.myElem_orig:hover {   //this is hover state, just changing bg color
  background-color: red;
}

.myElem_dragover { //new class, needs all attributes from original class
  top: 30px;
  left: 20px;
  ........ 
  background-color: red; //behaves the same like hover does
}

编辑:
忘了说,你还需要带回原来的类ondrop,否则div会留在dragover类中

【讨论】:

  • 我认为这个问题早于内置 HTML 可拖动属性的广泛使用,除非您正在执行自定义行为,否则这绝对是最简单的方法。
  • 这就是我要寻找的,而不是任何自定义行为。谢谢。
  • 我同意格雷格的观点。这个答案现在非常好,我觉得很快就会流行起来。
  • dragover/dragout 的一个缺点是,据我所知,它无法判断您将鼠标悬停在元素的哪一侧。假设它是您正在拖放排序的项目列表,如果您将鼠标悬停在项目的上半部分,您希望将拖动的内容放置在该项目之上。但是你只能看到你在上面悬停,现在是里面的位置。
  • @AndyMercer 在dragOver 事件中,您可以测试鼠标在哪一半上,向上或向下,并据此做出决定。例如,使用object.getBoundingClientRect(),您可以获得底部边框并从中减去鼠标 Y 坐标。你得到的价值比物体高度/2 更大或更爱
【解决方案3】:

有两种基本方法可以做到这一点:

  1. 跟踪 mousemove 并对 x/y 坐标做出反应
  2. 有一个透明目标,其z-index 高于拖动容器

第一个选项根本不使用鼠标悬停事件,但会给您相同的最终结果。

请注意,某些浏览器(即)不会在透明元素上触发mouseover,因此您必须通过设置透明的背景图像或将随机图像设置为背景并将其定位在元素外部来伪造它,例如这个:

element {
 background: url(/path/to/img) no-repeat -10000px 0;
}

【讨论】:

  • 可能会干扰被拖动的元素,这取决于他是如何设置的。
【解决方案4】:

jQuery-ui 对此有一个droppable plugin

该插件与draggable element 一起使用时将触发dropover 事件,该事件可以绑定到您需要的任何操作。

Mottie's answer to this question(包括演示)

【讨论】:

    【解决方案5】:

    稍微修改一下emrahgunduz发布的代码,特别是for循环,你也可以管理嵌套的droppable区域。

    var dragged, mousex, mousey, coordinates = [];
    
    var continueDragging = function(e) {
        // Change the location of the draggable object
        dragged.css({
            "left": e.pageX - (dragged.width() / 2),
            "top": e.pageY - (dragged.height() / 2)
        });
    
        // Check if we hit any boxes
        for (var i = coordinates.length - 1; i >= 0; i--) {
            if (mousex >= coordinates[i].left && mousex <= coordinates[i].right) {
                if (mousey >= coordinates[i].top && mousey <= coordinates[i].bottom) {
                    // Yes, the mouse is on a droppable area
                    // Lets change the background color
                    $('.droppable').removeClass("somethingover");
                    coordinates[i].dom.addClass("somethingover");
                    break;
                }
            } else {
                // Nope, we did not hit any objects yet
                coordinates[i].dom.removeClass("somethingover");
            }
        }
    
        // Keep the last positions of the mouse coord.s
        mousex = e.pageX;
        mousey = e.pageY;
    };
    
    var endDragging = function(e) {
        // Remove document event listeners
        $(document).unbind("mousemove", continueDragging);
        $(document).unbind("mouseup", endDragging);
    
        // Check if we hit any boxes
        for (var i = coordinates.length - 1; i >= 0; i--) {
            if (mousex >= coordinates[i].left && mousex <= coordinates[i].right) {
                if (mousey >= coordinates[i].top && mousey <= coordinates[i].bottom) {
                    // Yes, the mouse is on a droppable area
                    droptarget = coordinates[i].dom;
                    droptarget.removeClass("somethingover").addClass("dropped");
                    dragged.hide("fast", function() {
                        $(this).remove();
                    });
                }
            }
        }
    
        // Reset variables
        mousex = 0;
        mousey = 0;
        dragged = null;
        coordinates = [];
    };
    
    var startDragging = function(e) {
        // Find coordinates of the droppable bounding boxes
        $(".droppable").each(function() {
            var lefttop = $(this).offset();
            // and save them in a container for later access
            coordinates.push({
            dom: $(this),
            left: lefttop.left,
            top: lefttop.top,
            right: lefttop.left + $(this).width(),
            bottom: lefttop.top + $(this).height()
        });
    };
    
    // When the mouse down event is received
    if (e.type == "mousedown") {
        dragged = $(this);
        // Change the position of the draggable
        dragged.css({
            "left": e.pageX - (dragged.width() / 2),
            "top": e.pageY - (dragged.height() / 2),
            "position": "absolute"
        });
        // Bind the events for dragging and stopping
        $(document).bind("mousemove", continueDragging);
        $(document).bind("mouseup", endDragging);
    }
    
    // Start the dragging
    $(".draggable").bind("mousedown", startDragging);
    

    【讨论】:

      【解决方案6】:

      在 jsfiddle 示例中发现了一个小错误。 当您垂直离开放置区域时,放置区域仍然具有 'somethinghover' 类。

      http://jsfiddle.net/MAazv

      替换这个

      if (mousex >= coordinates[i].left && mousex <= coordinates[i].right) {
        if (mousey >= coordinates[i].top && mousey <= coordinates[i].bottom) {
          // Yes, the mouse is on a droppable area
          // Lets change the background color
          coordinates[i].dom.addClass("somethingover");
        }
      } else {
        // Nope, we did not hit any objects yet
        coordinates[i].dom.removeClass("somethingover");
      }

      http://jsfiddle.net/MAazv/122

      用这个:

      if (mousex >= coordinates[i].left && mousex <= coordinates[i].right && mousey >= coordinates[i].top && mousey <= coordinates[i].bottom) {
        // Yes, the mouse is on a droppable area
        // Lets change the background color
        coordinates[i].dom.addClass("somethingover");
      } else {
        // Nope, we did not hit any objects yet
        coordinates[i].dom.removeClass("somethingover");
      }

      【讨论】:

        【解决方案7】:

        另一种可能的解决方法是当被拖动元素阻塞其下元素的悬停或mouseenter事件时:

        pointer-events: none;

        如果将其应用于拖动的元素,则悬停应该仍然适用于下方的元素。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-10
          • 1970-01-01
          • 2021-08-22
          • 2012-01-21
          • 1970-01-01
          • 2016-04-27
          相关资源
          最近更新 更多