在IE中响应浏览器窗口外的onmousemove事件

29

在Internet Explorer 7中,body onmousemovedocument.onmousemove事件只有在鼠标位于浏览器窗口内时才会触发,而不是在鼠标移动到窗口外时触发。但是在Firefox中,当我把鼠标移到窗口外时,onmousemove事件被正确地调用。

我该如何在IE中设置一个事件,在浏览器窗口外被调用?

Google Maps在IE中可以实现这一点。如果您按住鼠标并将其移动到浏览器窗口外部,您会发现地图仍然在移动。

2个回答

71
(注:本答案仅适用于“标准”拖曳实现的mousedown -> mousemove -> mouseup。它不适用于HTML5拖放规范。)
允许拖动窗口外部是一个老问题,不同的浏览器有两种解决方法。
除了IE之外,当用户通过mousedown启动拖动操作时,浏览器会执行一些聪明的操作(所有这些都只是从观察中得出的):一种状态机开始处理窗口外部的鼠标移动的特殊情况:
1. 用户在文档内触发mousedown事件 2. 用户触发mousemove事件。即使是从文档外部(即窗口)触发,事件也会被触发。 3. 用户触发mouseup事件(在文档内或外)。从文档外部触发的mousemove事件将不再触发。
IE和旧版Firefox(至少到2.0.20)不表现出这种行为。在窗口外拖动就行不通。
IE和FF2的问题实际上在于一个元素是否可“选择”(见herehere)。如果拖动实现什么也不做(从而允许鼠标选择),那么该实现就不必考虑窗口外部的移动;浏览器将正常触发mousemove,用户可以自由地在窗口外部拖动。很好。
然而,通过让浏览器决定在mousemove中要做什么,你会得到这样一种效果,即浏览器认为用户试图“选择”某些内容(例如该元素),而不是移动它,并且在拖动期间,当鼠标进出该元素时,浏览器会疯狂地尝试突出显示该元素或其中的文本。
我看到的大多数拖放实现都会使用一个小技巧使被拖动的元素“不可选择”,从而完全控制mousemove以模拟拖动:
elementToDrag.unselectable = "on";
elementToDrag.onselectstart = function(){return false};
elementToDrag.style.userSelect = "none"; // w3c standard
elementToDrag.style.MozUserSelect = "none"; // Firefox

这个方法很好,但会导致拖动到窗口外面时出现问题。无论如何,要回答你的问题,为了让IE(所有版本)允许在窗口外拖动,请使用setCapture(并在鼠标释放时使用releaseCapture进行相反操作)。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Simple drag demo</title>
<style>
#dragme {
  position:absolute;
  cursor:move;
  background:#eee;
  border:1px solid #333;
  padding:10px;
}
</style>

<script>
function makeDraggable(element) {

  /* Simple drag implementation */
  element.onmousedown = function(event) {

    document.onmousemove = function(event) {
      event = event || window.event;
      element.style.left = event.clientX + 'px';
      element.style.top = event.clientY + 'px';
    };

    document.onmouseup = function() {
      document.onmousemove = null;

      if(element.releaseCapture) { element.releaseCapture(); }
    };

    if(element.setCapture) { element.setCapture(); }
  };

  /* These 3 lines are helpful for the browser to not accidentally 
   * think the user is trying to "text select" the draggable object
   * when drag initiation happens on text nodes.
   * Unfortunately they also break draggability outside the window.
   */
  element.unselectable = "on";
  element.onselectstart = function(){return false};
  element.style.userSelect = element.style.MozUserSelect = "none";
}
</script>
</head>
<body onload="makeDraggable(document.getElementById('dragme'))">

<div id="dragme">Drag me (outside window)</div>

</body>
</html>

这里可以看到演示

这正是Google地图所做的(我在2004年反向工程谷歌地图时发现的,当时它首次发布)。


1我认为只有在对文本节点进行拖动操作(即mousedown)时才会出现问题。元素/容器节点不会表现出相同的行为,可以在文档内或外拖动,只要用户在元素的“空白”部分按下鼠标即可。

2同样适用于文本节点的拖动启动。


这让我节省了很多时间和挫折!IE是需要Capture并且它有它的那个。其他浏览器会正确地检测到文档外的鼠标松开事件。 - Ed Bayiates
嗨,Crecent Fresh,我有一个需求,在每次mousedown后跟随一个mouseup的情况下,应该会弹出一个提示框。因此,在对文档进行mousedown后,如果用户将鼠标拖动到窗口外并在窗口外释放,则应弹出提示框。我该怎么做?我不太理解你的代码,因为它涉及选择和拖动等内容... - SexyBeast

2

1
谢谢。这是相当神秘的代码,但他似乎也在使用document.onmousemove,我想知道其中的秘密是什么? - Matthew Lock
我不知道,我没有仔细检查代码,但你也许可以使用Firebug(火狐浏览器)或Web Developer工具包(IE浏览器)来观察当你把鼠标移出浏览器时发生了什么。 - James Black
谢谢。当我移动鼠标时,我该如何在IE上观察Firebug或Web开发工具包中正在发生的事情?我已经在这两个工具中找了很久,但没有看到任何观察事件的方法。 - Matthew Lock
我注意到在walterzorn.com/dragdrop/dragdrop_e.htm中,只有图片可以通过鼠标移动窗口而不是底部的div示例。同样,在Google Maps中,你实际上是在拖动一张图片而不是HTML元素。也许这是IE的限制,只有图片拖动事件或其他东西可以在页面外工作? - Matthew Lock
你可以尝试这个,在控制台中查看:console.info("y大于x") - James Black
很想知道walterzorn.com网站到底去了哪里,自2010年7月以来它已经挂了一段时间了[参考http://forums.netobjects.com/showthread.php?9398-Walter-Zorn-s-website-is-down],而且现在还是无法访问!!! - Marco Demaio

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