【问题标题】:How to fire dragend event immediately如何立即触发 dragend 事件
【发布时间】:2020-05-12 19:53:40
【问题描述】:

我正在尝试解决在拖动到可拖动区域之外时立即触发dragend 事件的问题。例如,请注意以下视频中,将标签拖动到可拖动区域外时大约有 0.25 秒的延迟(当在可拖动区域内时,它会立即注册):https://gyazo.com/18d1afc32eb065d1f35896697ef0479e

这里是 JSFiddle:http://jsfiddle.net/radonirinamaminiaina/zfnj5rv4/

这个问题大约 7 年前在这里被问到:HTML5 dragend event firing immediately,但这似乎更像是一个浏览器限制,我认为我的问题有点不同。

有没有办法在将事件拖到可拖动区域之外时立即触发事件?比如在jfiddle的例子中,如果“This div is draggable”被拖到浏览器的左上角,让它零延迟地‘snap back’?

更新来自评论中的问题:这是我正在尝试做的一个示例,其中包含来自 Excel 数据透视表的 4s 视频:gyazo.com/3ccd1c3abd7f92d3410022a83b5c25b9。基本上,当用户在“拖动区域之外”拖动标签时,我希望能够立即删除该标签或触发显示该标签已被删除的动画。

【问题讨论】:

  • 所以要明确一点,您是在要求禁用放置位置与其最终位置之间的平滑过渡?
  • @Kaiido 我想描述它的最佳方式是展示我的意思。这是我尝试从 Excel 中的数据透视表执行的操作的示例:gyazo.com/3ccd1c3abd7f92d3410022a83b5c25b9。基本上,当用户将标签拖到“拖动区域之外”以立即删除该标签或触发显示该标签已被删除的动画时。
  • 为什么要听dragend事件?您应该通过将其委托给更大的父级(例如document)来监听该区域之外的放置事件。
  • 我们是在谈论用户将元素拖动到外部还是将其拖放到外部并拖放
  • @DanMacák 把它丢在外面。

标签: javascript browser dom-events


【解决方案1】:

您所描述的内容与在 Linux 和 Windows(桌面)系统上的 Chrome 和 Firefox 中的测试不一致。由于 COVID 情况,我无法轻松访问其他浏览器 + 操作系统组合(我不完全是 Apple 粉丝),但这是我制作的一个小提琴,您可以在其中测试任何其他此类组合:

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

它如何测试:它测量dropdragend 事件之间的毫秒差异。它还将它们中的每一个存储到一个数组中,该数组提供当前存储案例的minmaxavg 值。如您所见,0.15ms1.75ms 之间的差异有所不同,平均值为 ~0.5ms

因为它是一个实用的原型制作工具,所以我使用 Vue 来更新/显示统计数据,但这根本不会干扰正在测量的事件(您会注意到它们都发生并且在 Vue 之外进行测量并且数据更新发生在setTimeout() 中,以确保我根本不会干扰测试)。

不幸的是,Firefox 将 performance.now() 值四舍五入为 1ms,因此它不会为您提供亚毫秒级的 minmax 值,但平均值似乎与 Chrome 中的值一致(实际上在我的测试)。

以上建议您的前提是dragend 事件存在250ms 延迟是不准确的,除非这两个事件延迟相同的时间量。如果是这样,它将是可见的。四分之一秒是肉眼可见的。

我继续在上面的小提琴中添加了250ms 的可视化测试器。


另一个注意事项:查看您的演示视频,您似乎使用的是 Apple 设备,但它没有提供有关所使用浏览器的任何线索。如果我不得不猜测,我会说它是 Safari。

要禁用该动画,必须满足两个条件:

  • 您必须在 dragover 事件上致电 preventDefault()(您已经这样做了)
  • drop 事件需要在 dragend 触发时触发(根据 this answer

为了使第二个条件发生,如果事件的相关目标是<html>,您可以在dragleave 中调度drop。我真的没有看到其他选择:

document.addEventListener("dragleave", function(event) {
  if (event.relatedTarget.tagName === 'HTML') {
    document.dispatchEvent(new Event('drop'));
  }
})

注意:通过在拖出<html> 时调用drop,您将打破将内容从浏览器拖到任何其他程序的情况(AFAIK,这是 D&D 的预期用途之一)。此外,为了确保您只在实际拖出视口时才进行调度,您应该添加这个 CSS 位:body { min-height: 100vh; }

另外,如前所述,我现在无法在 Mac 上进行测试,所以我不保证这个 hack 有效。它应该,但是......这是苹果的实现,你知道吗?让我们说苹果一切皆有可能。也许是因为它被咬了,谁知道呢? :)

您可以测试 hack here


如果上面没有隐藏动画,this might。查看dragend 了解详情。 (这是一种尝试不事先触发drop(不符合原则),而是从dragend 触发它并重新发送一个可取消的dragend 模拟)。恕我直言,值得一试。

【讨论】:

  • 感谢您的全面回答。如果有帮助,我只是在评论中添加了另一个视频(是的,它在 mac 上)。
【解决方案2】:

这就是我的答案;不知道为什么,但它奏效了!

document.addEventListener("dragover", function( event ) {
    event.preventDefault();
}, false);

【讨论】:

    【解决方案3】:

    您可以尝试在删除这样的元素时自己触发 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 触发两次。

    我希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 2013-11-07
      • 2020-03-29
      • 2015-04-09
      • 1970-01-01
      • 2012-12-21
      • 2014-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多