JQuery:在dragstart事件上更改DOM会立即触发dragend吗?

use*_*084 17 javascript jquery

我遇到了Chrome和Opera的一个错误,我想知道它是否已知,如果有,是否有解决方案?

如果我在dragstart事件上更改DOM,它会立即触发dragend事件?!这是一个错误还是背后有一些原因?只发生在Chrome和Opera中.Firefox有效.

我很感激每一个答案.

$('body').on({
      dragstart: function(e) {
        
        dragProfilefieldSrcElformid = $(this).attr("data-profilefieldid-formid");
        e.dataTransfer = e.originalEvent.dataTransfer;
        e.dataTransfer.effectAllowed = 'move';
        e.dataTransfer.setData('text/html', $(this).attr("data-profilefieldid"));
        
        // Changing the DOM, fires the dragend Event in Chrome?
        $("#plugin_loginlogout_pfcontainer_" + dragProfilefieldSrcElformid).find(".plugin_loginlogout_pf_entryfield").addClass("highlight"); // This doesn't work in Chrome and Opera, but in Firefox
      },
      dragend: function() {
        console.log("dragend");
      }
      ".plugin_loginlogout_pf");
Run Code Online (Sandbox Code Playgroud)

编辑:

将DOM Change放在setTimeout函数中似乎解决了这个问题!

Ahm*_*eri 14

似乎不同的浏览器对长时间运行的操作表现出不同的行为.

JavaScript有一个线程,可以在同一队列中运行所有指令.每个队列项按顺序运行,一旦项完成执行,就会抓取并运行下一个项(来自队列).

长时间运行操作的罪魁祸首是您尝试为DOM带来的更改(我假设之前使用了大量搜索find(),将为每个匹配的元素运行DOM操作).

拖动元素时会发生什么,dragstart处理程序中的所有代码行,当您停止拖动时,dragend处理程序将分别推送到消息队列,以便顺序执行.然而,在停止拖动之前,DOM操作比执行dragend处理程序花费的时间更多(可能要多几毫秒),因此,它似乎dragend太快了.

注意:有时代码块会创建一个新事件,因此会被推送到浏览器事件队列的末尾(或者可能在正在运行的项目之后的某个位置),从而导致稍后的执行.(我想它的性质因浏览器而异.)

代码的DOM操作部分可能在Chrome和Opera中遇到这样的问题,但我不确定.

setTimeout(fn, 0)绝招

此类情况的解决方法是长时间运行的操作块setTimeout0时间包装在函数中.

(您可以将此视为告诉浏览器立即运行代码的一部分!但不是字面意思.)

一旦代码块完成执行,浏览器将搜索等待运行的可用项目,以及在第一个可用时刻将具有setTimeoutsetInterval将被推送到队列的项目.

在您的特定情况下,诀窍是setTimeout DOM更改的执行推迟到比事件处理程序更晚的时间(至少0几秒)dragend,从而给出了dragend在DOM更改后触发事件的印象.

有一个伟大的职位由@DVK 这里解释为什么setTimeout(fn, 0)有时是有用的.请检查他的JSfiddle(在Chrome中).

更新

正如@MojoJojo和@Pradeep所指出的那样,似乎Webkit浏览器(特别是旧版本的Chrome)存在drag事件问题.但是,我尝试重现Chrome版本47.0.2526.106(截至2016年1月11日的最新版本)中的错误,并且在drag没有任何违规行为的情况下触发了这些事件.

无论如何,即使存在错误,该setTimeout技巧仍然适用于该问题的正确解决方法.