小编典典

拖动子元素时触发父元素的“dragleave”

all

概述

我有以下 HTML 结构,并且已将dragenteranddragleave事件附加到<div id="dropzone">元素。

<div id="dropzone">
    <div id="dropzone-content">
        <div id="drag-n-drop">
            <div class="text">this is some text</div>
            <div class="text">this is a container with text and images</div>
        </div>
    </div>
</div>

问题

当我将文件拖到 上时<div id="dropzone">dragenter事件会按预期触发。但是,当我将鼠标移到子元素上时,例如<div id="drag-n-drop">dragenter会为该元素触发该事件<div id="drag-n- drop">,然后为该元素dragleave触发该事件<div id="dropzone">

如果我再次将鼠标悬停在<div id="dropzone">元素上,dragenter则再次触发事件,这很酷,但是随后dragleave为刚刚离开的子元素触发了事件,因此removeClass执行了指令,这并不酷。

这种行为是有问题的,原因有两个:

  1. 我只是将dragenter&附加dragleave到了,<div id="dropzone">所以我不明白为什么子元素也附加了这些事件。

  2. 我仍然在将<div id="dropzone">鼠标悬停在其子元素上时拖动元素,所以我不想dragleave开火!

jsFiddle

这是一个 jsFiddle 修补:http: //jsfiddle.net/yYF3S/2/

问题

那么......我怎样才能做到这一点,当我在元素上拖动文件时<div id="dropzone">dragleave即使我拖动任何子元素也不会触发......它应该只在我离开<div id="dropzone">元素时触发...... . 在元素边界内的任何地方悬停/拖动 不应 触发dragleave事件。

似乎 Google 和 Dropbox 已经解决了这个问题,但是他们的源代码被缩小/复杂,所以我无法从他们的实现中解决这个问题。


阅读 110

收藏
2022-07-29

共1个答案

小编典典

我终于找到了一个我满意的解决方案。实际上,我找到了几种方法来做我想做的事,但没有一个像当前的解决方案那样成功......在一个解决方案中,由于向#dropzone元素添加/删除边框,我经历了频繁的闪烁......在另一个解决方案中,边框如果您将鼠标悬停在浏览器之外,则永远不会被删除。

无论如何,我最好的 hacky 解决方案是:

var dragging = 0;

attachEvent(window, 'dragenter', function(event) {

    dragging++;
    $(dropzone).addClass('drag-n-drop-hover');

    event.stopPropagation();
    event.preventDefault();
    return false;
});

attachEvent(window, 'dragover', function(event) {

    $(dropzone).addClass('drag-n-drop-hover');

    event.stopPropagation();
    event.preventDefault();
    return false;
});

attachEvent(window, 'dragleave', function(event) {

    dragging--;
    if (dragging === 0) {
        $(dropzone).removeClass('drag-n-drop-hover');
    }

    event.stopPropagation();
    event.preventDefault();
    return false;
});

这工作得很好,但是在 Firefox 中出现了问题,因为 Firefox
是双重调用的dragenter,所以我的计数器关闭了。但是,它不是一个非常优雅的解决方案。

所以我接受了答案并将其应用于我的情况:

$.fn.dndhover = function(options) {

    return this.each(function() {

        var self = $(this);
        var collection = $();

        self.on('dragenter', function(event) {
            if (collection.size() === 0) {
                self.trigger('dndHoverStart');
            }
            collection = collection.add(event.target);
        });

        self.on('dragleave', function(event) {
            /*
             * Firefox 3.6 fires the dragleave event on the previous element
             * before firing dragenter on the next one so we introduce a delay
             */
            setTimeout(function() {
                collection = collection.not(event.target);
                if (collection.size() === 0) {
                    self.trigger('dndHoverEnd');
                }
            }, 1);
        });
    });
};

$('#dropzone').dndhover().on({
    'dndHoverStart': function(event) {

        $('#dropzone').addClass('drag-n-drop-hover');

        event.stopPropagation();
        event.preventDefault();
        return false;
    },
    'dndHoverEnd': function(event) {

        $('#dropzone').removeClass('drag-n-drop-hover');

        event.stopPropagation();
        event.preventDefault();
        return false;
    }
});

这是干净和优雅的,似乎在我迄今为止测试过的每个浏览器中都可以使用(还没有测试过 IE)。

2022-07-29