如何在 mousedown 元素之外捕获 mouseup 事件? (即正确的拖放?)
Posted
技术标签:
【中文标题】如何在 mousedown 元素之外捕获 mouseup 事件? (即正确的拖放?)【英文标题】:How to capture mouseup event outside of mousedown element? (i.e. for proper Drag-n-Drop?) 【发布时间】:2014-01-31 04:05:09 【问题描述】:如果在触发onmousedown
的元素之外释放鼠标按钮,则不会触发javascript onmouseup
event。
这会导致 JQuery UI 中的拖放错误:当鼠标按钮在其容器外释放时,JQuery draggable 元素不会停止拖动(因为元素在到达其父边界时将停止移动)。重现步骤:
转到http://jqueryui.com/draggable/。 向下拖动可拖动对象,直到鼠标离开周围的容器 松开鼠标按钮(此时未按下鼠标按钮) 将鼠标移回容器中 并且可拖动对象仍在被拖动。我希望一旦我释放鼠标按钮,拖动就会停止 - 无论它是在哪里释放的。我在最新的 Chrome 和 IE 中看到了这种行为。
有什么解决办法吗?
我知道我们可以在 mouseout
或 mouseleave
上停止拖动容器,但我想继续拖动,即使我在父容器之外,就像在 google maps 中一样(不管你在哪里松开鼠标,它总是停止拖动地图)。
【问题讨论】:
containment:'parent'
??? jsfiddle.net/4wX58
PS:我看到当鼠标按钮在文档外释放时,元素仍然可以拖动:(
【参考方案1】:
我找到了解决方案:只需将 mouseup
事件处理程序附加到 document
即可。然后它总是会取消,即使您在浏览器之外释放鼠标按钮。当然,这不是一个很好的解决方案,但显然,这是让拖动正常工作的唯一方法。
尝试以下解决方案:
您将看到“拖动结束”始终会发生,无论您在何处释放光标。 另外,为了防止在拖动时选择文本,我添加了一个unselectable
class。
let dragging = false;
const dragEl = document.querySelector('div');
const logEl = document.querySelector('pre');
dragEl.addEventListener('mousedown touchstart', (evt) =>
dragging = true;
dragEl.classList.add('unselectable');
logEl.textContent += 'drag START\n';
);
document.addEventListener('mouseup touchend', (evt) =>
if (dragging)
event.preventDefault();
dragEl.classList.remove('unselectable');
dragging = false;
logEl.textContent += 'drag END\n';
);
div
background: red;
.unselectable
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+/Edge */
user-select: none; /* Standard */
<div>drag me</div>
<hr>
LOG:
<p><pre></pre></p>
【讨论】:
谢谢,我只是在寻找如何跟踪文档外的光标(或者如果有办法)并看到了这个。我没有注意到谷歌地图做到了,尽管我注意到其他一些网站没有,而且当他们没有时很烦人。无论如何,感谢您发布您自己的答案,它帮助了我! 这只是将问题向上移动,如果您在文档(或窗口)之外释放鼠标按钮,您会遇到同样的问题。这可以通过我的答案中的解决方案来克服。 @Mog0 不确定您提出索赔的依据是什么?你试过了吗? 我试过了。但是,请注意日期——我的回答是将近 7.5 年前,而现代浏览器现在已经大不相同了。请注意,我下面的解决方案存在 IE8 和 Firefox 之间的兼容性问题!【参考方案2】:处理此问题的最佳方法是在 mousemove 事件处理程序中检查当前按钮状态。如果按钮不再向下,请停止拖动。
如果您将 mouseup 事件放在文档上,然后将问题向上移动,如果您在文档之外(甚至在浏览器窗口之外)释放按钮,原始问题仍然会出现。
以 jQuery 为例
$div.on("mousedown", function (evt)
dragging = true;
).on("mouseup", function (evt)
dragging = false;
).on("mousemove", function (evt)
if (dragging && evt.button == 0)
//Catch case where button released outside of div
dragging = false;
if (dragging)
//handle dragging here
);
您可以跳过 mouseup 事件处理程序,因为它会被 mousemove 捕获,但我认为它仍然存在时更具可读性。
【讨论】:
我更喜欢这个解决方案,除了我发现属性(至少在 Firefox 上)是 mouse.buttons,而不是 mouse.button。 mouse.button 对我来说总是 0 @ErinDrummond 发现得很好。 evt.button == 0 表示 IE 当鼠标在元素上时,这个解决方案仍然只将dragging
设置为false
,而不是在元素之外。此外,与您的说法相反,document
事件处理程序不同于所有其他事件处理程序,因为它不仅限于document
甚至浏览器窗口,并且将始终 立即触发,无论您在哪里停止拖动。
@Domi - 这是一个非常古老的讨论,经过 6 年的浏览器开发,在我看来是非常不公平的。答案是基于当时使用 IE7/8 和同等版本的情况,所以如果现代浏览器的行为不同,因为当时的规范发生了显着变化,我一点也不感到惊讶。
这部分没有改变。我投了反对票,因为它从未解决问题中所述的问题。以上是关于如何在 mousedown 元素之外捕获 mouseup 事件? (即正确的拖放?)的主要内容,如果未能解决你的问题,请参考以下文章