JavaScript. Подробное руководство, 6-е издание, стр. 259

Функция

<b>drag()</b>
принимает два аргумента. Первый - буксируемый элемент. Это может быть элемент, в котором возникло событие «mousedown», и содержащий его элемент (например, можно дать пользователю возможность ухватить мышью элемент, который выглядит как заголовок окна, и буксировать содержащий его элемент, который выглядит как окно). Однако в любом случае это должен быть элемент документа, абсолютно позиционированный с помощью CSS-атрибута position. Второй аргумент - объект события, полученный с событием «mousedown». Ниже приводится простой пример использования функции
<b>drag().</b>
В нем определяется элемент
<b>&lt;img&gt;,</b>
который пользователь может двигать мышью при нажатой клавише Shift:

<b>&lt;img src=”draggable.gif&quot;</b>

<b>  style=&quot;position:absolute; left:100px; top:100px;&quot;</b>

<b>  onmousedown=&quot;if (event.shiftKey) drag(this, event);&quot;&gt;</b>

Функция

<b>drag()</b>
преобразует координаты события «mousedown» в координаты документа, чтобы определить расстояние от указателя мыши до верхнего левого угла буксируемого элемента. При этом она использует вспомогательную функцию
<b>getScrollOffsets()</b>
из примера 15.8. Затем функция
<b>drag()</b>
регистрирует обработчики событий «mousemove» и «mouseup», которые последуют за событием «mousedown». Обработчик события «mousemove» отвечает за перемещение элемента документа, а обработчик события «mouseup» - за удаление себя и обработчика события «mousemove».

Важно отметить, что обработчики событий «mousemove» и «mouseup» регистрируются как перехватывающие обработчики. Это обусловлено тем, что пользователь может перемещать мышь быстрее, чем сможет перемещаться элемент документа, в результате чего некоторые события «mousemove» могут возникать за пределами буксируемого элемента. В фазе всплытия эти события просто не будут передаваться нужным обработчикам. В отличие от стандартной модели модель событий, реализованная в IE, не поддерживает фазу перехвата, но она поддерживает специализированный метод

<b>setCapture(),</b>
позволяющий перехватывать события мыши в подобных случаях. Пример наглядно демонстрирует, как действует этот метод.

Наконец, обратите внимание, что функции

<b>moveHandler()</b>
и
<b>upHandler()</b>
определены внутри функции
<b>drag().</b>
Благодаря тому, что они определены во вложенной области видимости, эти функции могут пользоваться аргументами и локальными переменными функции
<b>drag(),</b>
что существенно упрощает их реализацию.

Пример 17.2. Буксировка элементов документа

<b>/**</b>

<b>* Drag.js: буксировка абсолютно позиционированных HTML-элементов.</b>

<b>*</b>

<b>* Этот модуль определяет единственную функцию drag(), которая должна вызываться</b>

<b>* из обработчика события onmousedown. Последующие события mousemove будут вызывать</b>

<b>* перемещение указанного элемента. Событие mouseup будет завершать буксировку.</b>

<b>* Эта реализация действует в обеих моделях событий, стандартной и IE.</b>

<b>* Использует функцию getScrollOffsets(), представленную выше в книге.</b>

<b>*</b>

<b>* Аргументы:</b>

<b>*</b>

<b>* elementToDrag: элемент, принявший событие mousedown или содержащий его элемент.</b>

<b>* Этот элемент должен иметь абсолютное позиционирование. Значения его свойств style.left</b>

<b>* и style.top будут изменяться при перемещении указателя мыши пользователем.</b>

<b>*</b>

<b>* event: объект Event, полученный обработчиком события mousedown.</b>

<b>**/</b>

<b>function drag(elementToDrag, event) {</b>

<b>  // Преобразовать начальные координаты указателя мыши в координаты документа</b>

<b>  var scroll = getScrollOffsets(): // Вспомогательная функция, объявленная</b>

<b>                                   // где-то в другом месте</b>

<b>  var startX = event.clientX + scroll.x;</b>

<b>  var startY = event.clientY + scroll.y;</b>

<b>  // Первоначальные координаты (относительно начала документа) элемента, который</b>

<b>  // будет перемещаться. Так как elementToDrag имеет абсолютное позиционирование,</b>

<b>  // предполагается, что его свойство offsetParent ссылается на тело документа,</b>

<b>  var origX = elementToDrag.offsetLeft;</b>

<b>  var origY = elementToDrag.offsetTop;</b>

<b>  // Найти расстояние между точкой события mousedown и верхним левым углом элемента.</b>

<b>  // Это расстояние будет учитываться при перемещении указателя мыши,</b>

<b>  var deltaX = startX - origX;</b>

<b>  var deltaY = startY - origY;</b>

<b>  // Зарегистрировать обработчики событий mousemove и mouseup,</b>

<b>  // которые последуют за событием mousedown,</b>

<b>  if (document.addEventListener) { // Стандартная модель событий</b>

<b>    // Зарегистрировать перехватывающие обработчики в документе</b>

<b>    document.addEventListener( &quot;mousemove&quot;, moveHandler, true);</b>

<b>    document.addEventListener(&quot;mouseup”, upHandler, true);</b>