如何使dragover / dragleave不粗略?

时间:2015-11-30 23:39:37

标签: jquery html5 drag-and-drop

这是我的代码:

var dragStart = _.debounce(function () {
    console.log("START");
    $dropIndicator.appendTo(document.body).show();
}, 10, {
    leading: true,
    trailing: false
});

var dragStop = _.debounce(function () {
    console.log("STOP");
    $dropIndicator.hide();
}, 10, {
    leading: false,
    trailing: true
});

$(window)
    .on('dragover', function (ev) {
        ev.preventDefault();
        ev.originalEvent.dataTransfer.dropEffect = 'copy';
        dragStop.cancel();
        dragStart();
    })
    .on('dragleave', function (ev) {
        ev.preventDefault();
        dragStop();
    })
    .on('drop', function (ev) {
        ev.preventDefault();
        dragStop();
        uploadFiles(ev.originalEvent.dataTransfer.files);
    });

如果我将文件拖到窗口顶部,我会看到我的掉落指示符。但是,当在窗口上移动文件时(不会将鼠标从窗口移开),我看到“STOP”会定期调用。

在“拖动的元素或文本选择留下有效的放置目标”之前,不应该调用

MDN says dragleave - 但我的目标是窗口,我从未离开过。

为什么要被召唤?这会导致我的掉落指示器闪烁,或者更糟糕的是,有时根本没有捕获掉落事件。

我把去抖动放在那里以减轻问题,但无论有没有去抖,它仍然是一个问题。

1 个答案:

答案 0 :(得分:2)

我尝试了几个不同的库,但它们都没有特别好用。这是我提出的最佳解决方案:

var $dropIndicator = $('#drop-indicator');

let dragOpen = false;
let dragElements = new Set();
let closeTimer = null;

function showDragIndicator() {
    clearTimeout(closeTimer);
    if(!dragOpen) {
        $dropIndicator.appendTo(document.body).show();
        dragOpen = true;
    }
}

function hideDragIndicator() {
    clearTimeout(closeTimer);
    closeTimer = setTimeout(() => {
        hideDragIndicatorNow();
    }, 100);
}

function hideDragIndicatorNow() {
    if(dragOpen) {
        $dropIndicator.hide();
        dragOpen = false;
        dragElements.clear();
    }
}

$(window)
    .on('drop', function(ev) {
        ev.preventDefault();
        hideDragIndicator();
        uploadFiles(ev.originalEvent.dataTransfer.files);
    })
    .on('dragover', function(ev) {
        ev.preventDefault();
        showDragIndicator();
    })
    .on('dragenter', function(ev) {
        ev.preventDefault();
        dragElements.add(ev.target);
        showDragIndicator();
    })
    .on('dragleave', function(ev) {
        ev.preventDefault();
        dragElements.delete(ev.target);
        if(dragElements.size === 0) {
            hideDragIndicator();
        }
    })
    .on('mousemove', function(ev) {
        ev.preventDefault();
        hideDragIndicatorNow();
    });

适用于Ubuntu的Firefox和Chrome以及Windows上的Windows和IE11。

Firefox Windows有一个错误,当您在窗口上拖动文件然后再次退回时,dragleave事件不会触发,这就是为什么我添加了mousemove事件以便将鼠标移回窗口时,拖放指示器至少会清除。

隐藏延迟是必要的,以防止一些闪烁,即使我已经跟踪触发进入/离开的所有元素,他们似乎发射太多。

must绑定dragover事件,以便在IE中使用。