JQuery:更改dragstart事件上的DOM会立即触发dragend
JQuery: Changing the DOM on dragstart event fires dragend immediately?
我遇到了Chrome和Opera的一个bug,我想知道它是否已知,如果已知,有解决方案吗?
如果我更改dragstart事件的DOM,它会立即引发dragend事件?!这是一个bug还是背后有什么原因?只在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");
编辑:
将DOM更改放在setTimeout函数中似乎可以解决问题!
不同的浏览器似乎对长时间运行的操作表现出不同的行为。
JavaScript有一个单独的线程,可以在同一队列中运行所有指令。每个队列项目都按顺序运行,一旦项目完成执行,就会抓取并运行下一个项目(队列中的)。
长时间运行操作的罪魁祸首是您试图对DOM进行的更改(我认为之前会使用find()
进行大量搜索,为每个匹配的元素运行DOM操作)。
拖动元素时会发生的情况是,
dragstart
处理程序中的所有代码行,以及停止拖动时,dragend
处理程序会分别推送到消息队列中,以便串行执行。但是,在停止拖动之前,执行DOM操作所花费的时间(可能比执行dragend
处理程序多出几毫秒)要多,因此,dragend
似乎过早启动。
注意:有时代码块会创建一个新事件,因此会被推到浏览器事件队列的末尾(或可能在正在运行的项目之后的某个位置),从而导致稍后执行。(我想它的性质因浏览器而异。)
代码的DOM操作部分可能在Chrome和Opera中面临这样的问题,尽管我不确定。
setTimeout(fn, 0)
技巧
这种情况的解决方法是用0
时间将长时间运行的操作块封装在setTimeout
函数中。
(你可以认为这是告诉浏览器在中运行代码的部分,根本没有时间!,但不是字面意思。)
一旦代码块执行完毕,浏览器将搜索等待运行的可用项目,并且具有setTimeout
或setInterval
的项目将在第一个可用时刻被推送到队列中。
在您的特定情况下,诀窍是setTimeout
将DOM更改的执行推迟到比dragend
事件处理程序晚的时间(至少0
秒),从而给人一种dragend
事件在DOM更改后启动的印象。
@DVK在这里有一篇很棒的帖子解释了为什么setTimeout(fn, 0)
有时很有用。请检查他(在Chrome中)的JSfiddle。
更新
正如@MojoJojo和@Pradeep所指出的,Webkit浏览器(尤其是旧版本的Chrome)似乎存在drag
事件问题。然而,我试图在Chrome版本47.0.2526.106(截至2016年1月11日的最新版本)中重现该错误,drag
事件在没有任何异常的情况下启动。
无论如何,即使存在错误,setTimeout
技巧仍然适用于解决该问题
只需尝试将DOM操作置于dragstart的drag事件中即可:)
我认为这是一个小故障/bug,否则我们可以说浏览器就是这样工作的,因为我们正在进行DOM操作,这可能会导致重新绘制整个DOM,在dragStart事件中操作DOM会导致这个问题,将DOM操作改为dragEnter可能会解决这个问题。
另一个解决方案可能是设置您已经提到的setTimeout。
这似乎是Chrome中的一个问题https://groups.google.com/a/chromium.org/forum/?fromgroups=#!msg/铬虫/YHs3orFC8Dc/ryT25b7J NwJ
你使用的是什么版本的Chrome?
没有jquery工作
var draggable = document.getElementById('draggable'),
test = document.getElementById('test');
document.addEventListener("dragend", function(event) {
// reset the transparency
console.log('dragend');
}, false);
draggable.addEventListener('dragstart', function(event) {
test.style.color = 'red';
draggable.style.backgroundColor = 'gray';
}, false);
http://jsfiddle.net/nwkv75ot/4/
我发现setTimeout()解决方法在Firefox中非常有缺陷。例如,当您在拖动后立即释放鼠标按钮时,dragstart中的上下文可能不再可访问,脚本可能会崩溃。特别是与dragend事件结合使用时。
我创建了以下程序,使我的脚本更加可靠:
$('html').on('dragstart', '.somelement', function(e){
// Bind 'drag' event only once (gets triggered every 350ms)
$('html').one('drag', function(){
// modify DOM here
});
});
$('html').on('dragend', '.somelement', function(e){
// Edge might fire 'dragend' before executing the 'drag' event within 'dragstart'
$('html').unbind('drag');
});
- 在单击任何位置时隐藏元素,而不检查每次DOM单击
- 是否有任何snippet或jQuery插件可以列出easylist.txt模式匹配的DOM中的所有元素
- 在不使用JQuery的情况下隐藏DOM中的选定元素
- 如何在DOM元素上按类型构建此函数
- Windows形成web浏览器控件和Javascript更改的DOM
- Datatables:通过DOM数据源中的名称引用列
- 在DOM中查找一个模式并替换它's的内容使用jquery
- DOM事件通过JSON转换为java
- 将DOM节点值与字符串Javascript进行比较
- delete在Object上效率低下,但在DOM Element's的数据属性,与null out相比
- 流星中DOM的繁殖
- DOM元素和angular元素之间的主要区别是什么
- 当带有渲染器的DOM元素不在屏幕顶部时,移动了场景的坐标
- 如何将Knockout.JS与服务器已经在DOM中呈现的数据同步
- PHP-如何重定向到同一页面并更改DOM's
- 如何使用ViewCompiler手动编译DOM的一部分
- 从popup.js|Chrome扩展访问DOM
- React DOM offsetHeight before rendering
- DOM导航-上一个同级未定义
- JQuery:更改dragstart事件上的DOM会立即触发dragend