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

Mat*_*ock 26 javascript internet-explorer javascript-events

在Internet Explorer 7中,onmousemovedocument.onmousemove事件仅在鼠标位于浏览器窗口内时触发,而不是在外部时触发.然而在Firefox中,当我移出浏览器窗口时,onmousemove事件被正确调用.

如何设置在IE浏览器窗口外调用的事件?

Google地图在IE中执行此操作.如果按住鼠标按钮并将鼠标移动到浏览器窗口之外,则可以看到地图仍在移动.

Cre*_*esh 66

(注意:此答案仅指"标准"拖动实现mousedown -> mousemove -> mouseup.它不适用于HTML5拖动规范).

允许在浏览器窗口外拖动是一个老问题,不同的浏览器以两种方式解决了这个问题.

除了IE之外,当用户通过mousedown浏览器启动拖动操作已经做了一些整洁的事情(这一切都只是来自观察):一种状态机开始处理窗口外鼠标移动的特殊情况:

  1. 用户mousedown在内部触发事件document
  2. 用户触发mousemove事件.即使从外部(即窗口)触发事件也会触发document
  3. 用户触发mouseup事件(内部或外部document).mousemove从文档外部触发的事件不再触发

IE和旧版本的Firefox [最晚2.0.20]不会出现这种行为.在窗口外拖动不起作用1.

IE和FF2的问题实际上在于元素是否"可选"(参见此处此处).如果拖动实现什么都不做(从而允许鼠标选择),那么所述实现不必考虑窗口外的移动; 浏览器将继续mousemove正常启动并允许用户在窗口外自由拖动.尼斯.

然而,通过让浏览器决定在mousemove上做什么,你得到这种效果,浏览器认为用户试图"选择"某些东西(例如元素),而不是移动它,并继续疯狂地尝试突出显示元素或当拖动期间鼠标穿过或离开元件时,其中的文本.

我见过的大多数拖拽实现都会使元素被拖动"无法选择",从而完全控制mousemove模拟拖动:

elementToDrag.unselectable = "on";
elementToDrag.onselectstart = function(){return false};
elementToDrag.style.userSelect = "none"; // w3c standard
elementToDrag.style.MozUserSelect = "none"; // Firefox
Run Code Online (Sandbox Code Playgroud)

这很好用,但打破窗外拖动.2

无论如何,要回答你的问题,让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>
Run Code Online (Sandbox Code Playgroud)

演示可以在这里看到.

这正是谷歌地图的作用(正如我自2004年首次发布时反向工程谷歌地图所发现的那样).


1 我相信它实际上只mousedown在文本节点上启动拖动操作(即)时才会中断.元素/容器节点不会表现出相同的行为,并且可以在文档内部或外部拖动,前提是用户将鼠标放在元素的"空"部分上

2 同样,对于文本节点的拖动启动.