我遇到的问题是,一个元素的dragleave事件是在悬停该元素的子元素时触发的。同样,当再次悬停回父元素时,dragenter不会被触发。

我做了一个简化的小提琴:http://jsfiddle.net/pimvdb/HU6Mk/1/。

HTML:

<div id="drag" draggable="true">drag me</div>

<hr>

<div id="drop">
    drop here
    <p>child</p>
    parent
</div>

使用以下JavaScript:

$('#drop').bind({
                 dragenter: function() {
                     $(this).addClass('red');
                 },

                 dragleave: function() {
                     $(this).removeClass('red');
                 }
                });

$('#drag').bind({
                 dragstart: function(e) {
                     e.allowedEffect = "copy";
                     e.setData("text/plain", "test");
                 }
                });

它应该做的是,当拖拽一些东西时,通过将drop div设置为红色来通知用户。这是可行的,但是如果你拖动到p子元素中,拖动键就会触发,div就不再是红色了。移动回下拉div也不会使它再次变红。有必要完全移出拖放div,并再次拖回它,使其变为红色。

是否有可能阻止dragleave在拖动到子元素时发射?

2017年更新:TL;DR,查找CSS指针事件:无;如@ h.d.所述。在现代浏览器和IE11中都能运行。


当前回答

问题是当鼠标移动到子元素前面时,dragleave事件被触发。

我已经尝试了各种方法来检查e.target元素是否与this元素相同,但没有任何改进。

我修复这个问题的方式有点hack,但工作100%。

dragleave: function(e) {
               // Get the location on screen of the element.
               var rect = this.getBoundingClientRect();

               // Check the mouseEvent coordinates are outside of the rectangle
               if(e.x > rect.left + rect.width || e.x < rect.left
               || e.y > rect.top + rect.height || e.y < rect.top) {
                   $(this).removeClass('red');
               }
           }

其他回答

我写了一个叫做Dragster的小库来处理这个确切的问题,除了在IE中默默不做任何事情外,它可以在任何地方工作(IE不支持DOM事件构造器,但使用jQuery的自定义事件很容易写一些类似的东西)

在花了这么多小时后,我得到的建议完全按照预期工作。我只想在文件被拖拽时提供提示,而文档拖拽,拖拽会在Chrome浏览器上引起痛苦的闪烁。

这就是我解决它的方法,也为用户提供了适当的提示。

$(document).on('dragstart dragenter dragover', function(event) {    
    // Only file drag-n-drops allowed, http://jsfiddle.net/guYWx/16/
    if ($.inArray('Files', event.originalEvent.dataTransfer.types) > -1) {
        // Needed to allow effectAllowed, dropEffect to take effect
        event.stopPropagation();
        // Needed to allow effectAllowed, dropEffect to take effect
        event.preventDefault();

        $('.dropzone').addClass('dropzone-hilight').show();     // Hilight the drop zone
        dropZoneVisible= true;

        // http://www.html5rocks.com/en/tutorials/dnd/basics/
        // http://api.jquery.com/category/events/event-object/
        event.originalEvent.dataTransfer.effectAllowed= 'none';
        event.originalEvent.dataTransfer.dropEffect= 'none';

         // .dropzone .message
        if($(event.target).hasClass('dropzone') || $(event.target).hasClass('message')) {
            event.originalEvent.dataTransfer.effectAllowed= 'copyMove';
            event.originalEvent.dataTransfer.dropEffect= 'move';
        } 
    }
}).on('drop dragleave dragend', function (event) {  
    dropZoneVisible= false;

    clearTimeout(dropZoneTimer);
    dropZoneTimer= setTimeout( function(){
        if( !dropZoneVisible ) {
            $('.dropzone').hide().removeClass('dropzone-hilight'); 
        }
    }, dropZoneHideDelay); // dropZoneHideDelay= 70, but anything above 50 is better
});

只要检查拖过的元素是否是子元素,如果是,那么不要删除'拖过'样式的类。非常简单,对我来说很有用:

 $yourElement.on('dragleave dragend drop', function(e) {
      if(!$yourElement.has(e.target).length){
           $yourElement.removeClass('is-dragover');
      }
  })

pimvdb…

你为什么不试试用滴胶代替拖胶呢?这对我很管用。希望这能解决你的问题。

请查看jsFiddle: http://jsfiddle.net/HU6Mk/118/

$('#drop').bind({
                 dragenter: function() {
                     $(this).addClass('red');
                 },

                 drop: function() {
                     $(this).removeClass('red');
                 }
                });

$('#drag').bind({
                 dragstart: function(e) {
                     e.allowedEffect = "copy";
                     e.setData("text/plain", "test");
                 }
                });

我有一个类似的问题-我的代码隐藏dropzone dragleave事件的身体被触发时悬停子元素使dropzone闪烁在谷歌Chrome。

我能够通过调度隐藏dropzone的函数来解决这个问题,而不是立即调用它。然后,如果触发另一个拖拽或拖拽,则取消预定的函数调用。

body.addEventListener('dragover', function() {
    clearTimeout(body_dragleave_timeout);
    show_dropzone();
}, false);

body.addEventListener('dragleave', function() {
    clearTimeout(body_dragleave_timeout);
    body_dragleave_timeout = setTimeout(show_upload_form, 100);
}, false);

dropzone.addEventListener('dragover', function(event) {
    event.preventDefault();
    dropzone.addClass("hover");
}, false);

dropzone.addEventListener('dragleave', function(event) {
    dropzone.removeClass("hover");
}, false);