我遇到的问题是,一个元素的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中都能运行。


当前回答

一个非常简单的解决方案是使用CSS属性pointer-events。只需在拖拽每个子元素时将其值设置为none。这些元素将不再触发与鼠标相关的事件,因此它们将不会捕获鼠标在其上,从而不会触发父元素上的dragleave。

不要忘记在完成拖动时将此属性设置为auto;)

其他回答

我有一个类似的问题-我的代码隐藏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);

不确定这是否跨浏览器,但我在Chrome中测试,它解决了我的问题:

我想拖放一个文件在整个页面,但我的dragleave被解雇时,我拖过子元素。我的解决方法是查看鼠标的x和y:

我有一个div覆盖我的整个页面,当页面加载我隐藏它。

当你拖拽文件时,我显示它,当你拖拽到父文件时,它处理它,当你离开父文件时,我检查x和y。

$('#draganddrop-wrapper').hide();

$(document).bind('dragenter', function(event) {
    $('#draganddrop-wrapper').fadeIn(500);
    return false;
});

$("#draganddrop-wrapper").bind('dragover', function(event) {
    return false;
}).bind('dragleave', function(event) {
    if( window.event.pageX == 0 || window.event.pageY == 0 ) {
        $(this).fadeOut(500);
        return false;
    }
}).bind('drop', function(event) {
    handleDrop(event);

    $(this).fadeOut(500);
    return false;
});

试着使用event。eventphase。只有输入目标时,它才会被设置为2 (Event.AT_TARGET),否则它会被设置为3 (Event.BUBBLING_PHASE)。

我已经使用eventPhase来绑定或取消绑定dragleave事件。

$('.dropzone').on('dragenter', function(e) {

  if(e.eventPhase === Event.AT_TARGET) {

    $('.dropzone').addClass('drag-over');

    $('.dropzone').on('dragleave', function(e) {
      $('.dropzone').removeClass('drag-over');
    });

  }else{

    $('.dropzone').off('dragleave');

  }
})

圭多

解决. . !

为ex声明任意数组:

targetCollection : any[] 

dragenter: function(e) {
    this.targetCollection.push(e.target); // For each dragEnter we are adding the target to targetCollection 
    $(this).addClass('red');
},

dragleave: function() {
    this.targetCollection.pop(); // For every dragLeave we will pop the previous target from targetCollection
    if(this.targetCollection.length == 0) // When the collection will get empty we will remove class red
    $(this).removeClass('red');
}

不需要担心子元素。

   private onDragLeave(e) {
     e.preventDefault();
     e.stopPropagation();

    if (this.isEventFromChild(e)) {
      return;
    }

    this.isDragOver = false;
  }
  
  private isEventFromChild(e): boolean {
    //relatedTarget is null on Safari, so we take it from coordinates
    const relatedTarget = e.relatedTarget || document.elementFromPoint(e.clientX, e.clientY);
    return e.currentTarget.contains(relatedTarget);
  }