Ответ 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 Опять же, для инициации перетаскивания на текстовых узлах.