Подтвердить что ты не робот

Ответ на событие onmousemove за пределами окна браузера в IE

В Internet Explorer 7 тело onmousemove или document.onmousemove события только срабатывают, когда мышь находится внутри окна браузера, а не когда она находится снаружи. Однако в Firefox событие onmousemove вызывается правильно, когда я выхожу за пределы окна браузера.

Как настроить событие для вызова вне окна браузера в IE?

Карты Google делает это в IE. Если вы удерживаете кнопку мыши и перемещаете мышь за пределы окна браузера, вы можете видеть, что карта все еще перемещается.

4b9b3361

Ответ 1

(Примечание: этот ответ относится исключительно к "стандартной" реализации перетаскивания mousedown -> mousemove -> mouseup. Он не применим к спецификации перетаскивания HTML5).

Разрешение перетаскивания за пределы окна браузера является старой проблемой, которую разные браузеры решили двумя способами.

За исключением IE, когда пользователь инициирует операцию перетаскивания через mousedown, браузеры сделали что-то аккуратное (и это все просто из наблюдения): какой-то тип statemachine срабатывает, чтобы обрабатывать специальный случай движений мыши вне окно:

  • Пользователь запускает событие mousedown внутри document
  • Пользователь запускает событие mousemove. Событие срабатывает даже при срабатывании извне document (то есть в окне)
  • Пользователь запускает событие 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

Это хорошо работает, , но перерывы перетаскиваются за пределы окна. 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>

Демо можно увидеть здесь.

Это именно то, что делают карты Google (как я обнаружил, так как обратные разработки google maps появились еще в 2004 году, когда он был впервые выпущен).


1 Я считаю, что на самом деле он прерывается только при запуске операции перетаскивания (т.е. mousedown) в текстовом поле. Узлы элементов/контейнеров не проявляют одинакового поведения и могут перемещаться внутри или снаружи документа, при условии, что пользователь замалчивает "пустую" часть элемента

2 Опять же, для инициации перетаскивания на текстовых узлах.