如何立即触发dragend事件

5
我正在尝试解决问题,即在拖动到可拖动区域外部时立即触发dragend事件。例如,请注意以下视频中,在将标签拖到可拖动区域外部时存在约0.25秒的延迟(当在其中时,它会立即注册):https://gyazo.com/18d1afc32eb065d1f35896697ef0479e
以下是JSFiddle:http://jsfiddle.net/radonirinamaminiaina/zfnj5rv4/
此问题大约7年前在这里提出:HTML5 dragend event firing immediately,但我认为这似乎更像是当时浏览器的限制,并且我认为我的问题有很大不同。
是否有办法在拖到可拖动区域外部时立即触发事件?例如,在jfiddle示例中,如果将“This div is draggable”拖到浏览器左上角,则可以零延迟地“弹回”?
更新来自评论中的问题:以下是一个来自Excel中数据透视表的4秒视频示例,可以看到我想要做的事情:https://gyazo.com/3ccd1c3abd7f92d3410022a83b5c25b9。基本上,当用户将标签“拖到可拖动区域外部”时,我希望能够立即删除该标签或触发动画以显示已删除该标签。

那么明确一下,您是在询问是否要禁用拖放操作中物体平滑过渡到最终位置的效果? - Kaiido
为什么要监听dragend事件?你应该通过委托给更大的父元素(例如document)来监听那个区域外的drop事件。 - Kaiido
我们是在讨论用户将元素拖动到外面,还是拖放到外面? - Dan Macak
@DanMacák 将其丢在外面。 - David542
和 @tao 一样,我在 Windows 上无法重现它,而且我这里没有 Mac。你在 Safari、Chrome 等浏览器上是否也有同样的情况? - Dan Macak
显示剩余3条评论
3个回答

6
这对我来说是个正确答案;不确定为什么,但它有效了!
document.addEventListener("dragover", function( event ) {
    event.preventDefault();
}, false);

3
你所描述的情况与在Linux和Windows(桌面)系统中使用Chrome和Firefox进行测试不一致。由于COVID的情况,我无法轻松地访问其他浏览器+操作系统组合(我并不是苹果的粉丝),但这里有一个我制作的Fiddle,你可以在其中测试任何其他这样的组合:

https://jsfiddle.net/websiter/9d7cfbmx/embedded/result/#Result

如何测试:它测量了“放置(drop)”和“拖放结束(dragend)”事件之间的毫秒差异。它还将它们中的每一个存储到数组中,提供当前存储案例的“最小值(min)”,“最大值(max)”和“平均值(avg)”。正如您所看到的,这个差异在“0.15ms”和“1.75ms”之间变化,平均值为“~0.5ms”。
因为它是一个实用的原型工具,我使用Vue来更新/显示统计信息,但这不应该影响到被测量的事件(您会注意到它们都发生并且在Vue之外被测量,并且数据更新在一个“setTimeout()”中进行,以确保我完全没有干扰测试)。
不幸的是,Firefox将“performance.now()”的值舍入到“1ms”,因此它不会给出亚毫秒的“最小值”和“最大值”,但平均值似乎与Chrome中的一致(实际上在我的测试中稍微小一些)。
上述内容表明你的前提假设,即在“dragend”事件上存在250毫秒的延迟,是不准确的,除非两个事件都被同样长的时间延迟。如果是这种情况,那么它将是可见的。人眼可以感知四分之一秒的时间。我已经为上述示例添加了一个250毫秒的可视化测试器。
另外注意:从您的演示视频来看,您似乎在使用苹果设备,但无法确定所使用的浏览器。如果我要猜测,我会说它是Safari。
要禁用该动画,必须满足两个条件:
  • 您必须在dragover事件上调用preventDefault()(您已经这样做了)
  • drop事件需要在dragend事件之前被触发(根据this answer
为了满足第二个条件,您可以在dragleave事件中分派drop,如果事件的相关目标是<html>。我真的看不到其他选择:
document.addEventListener("dragleave", function(event) {
  if (event.relatedTarget.tagName === 'HTML') {
    document.dispatchEvent(new Event('drop'));
  }
})

注意:当从 <html> 拖动时调用 drop,您会破坏将任何东西从浏览器拖出到任何其他程序中的情况(这是 D&D 的预期用途之一)。此外,为了确保仅在实际从视口拖出时进行分派,您应添加此 CSS 代码:body { min-height: 100vh; }
另外,如前所述,我现在没有办法在 Mac 上测试,因此不能保证这个技巧能够正常工作。它应该可以,但是...这是苹果的实现,你知道吗?我们只能说,在苹果身上,任何事情都有可能发生。也许是因为被咬了,谁知道呢? :)
您可以在 这里 进行测试。
如果上述方法无法隐藏动画,这个方法也许可以。查看 dragend 以获取详细信息。(这是一种尝试,在原则上不触发 drop,而是从 dragend 触发它并重新分派可取消的 dragend 模拟)。在我看来,值得一试。

谢谢您提供这么全面的答案。如果有帮助的话,我在评论中添加了另一个视频(是关于Mac的)。 - David542

0

当你像这样放置一个元素时,你可以尝试自己触发dragend事件:

document.addEventListener("drop", function( event ) {
    event.preventDefault();

    // currentTarget refers to document because I added the listener on it.
    event.currentTarget.dispatchEvent(new Event('dragend'));
}, false);

我无法测试是否会移除动画,因为这似乎是由MacOS引起的行为?

另外请注意,这可能会导致事件dragend触发两次。

希望这能帮到你!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接