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

17.5. События мыши

17.5. События мыши

С мышью связано довольно много событий. Все они перечислены в табл. 17.1. Все события мыши, кроме «mouseenter* и «mouseleave», всплывают. Для событий «click», возникающих в ссылках и кнопках отправки форм, предусматриваются действия по умолчанию, которые можно отменить. Теоретически имеется возможность отменить событие «contextmenu* и предотвратить появление контекстного меню, но некоторые броузеры имеют параметры настройки, которые делают это событие неотменяемым.


Объект, передаваемый обработчикам событий от мыши, имеет свойства clientX и clientY, определяющие координаты указателя относительно окна. Чтобы преобразовать их в координаты документа, к ним необходимо добавить позиции полос прокрутки окна (как показано в примере 15.8).

Свойства altKey, ctrlKey, metaKey и shiftKey определяют состояния различных клавиш-модификаторов, которые могли удерживаться в нажатом состоянии в момент события: с их помощью можно отличать простой щелчок от щелчка с нажатой клавишей Shift, например.

Свойство button определяет, какая кнопка мыши удерживалась в нажатом состоянии в момент события. Однако разные броузеры записывают в это свойство разные значения, поэтому его сложно использовать переносимым способом. Подробности смотрите в справочной статье Event в четвертой части книги. Некоторые броузеры возбуждают событие «click» только в случае щелчка левой кнопкой. Поэтому, если потребуется обрабатывать щелчки другими кнопками, следует использовать события «mousedown» и «mouseup». Событие «contextmenu» обычно сигнализирует о том, что был выполнен щелчок правой кнопкой, но, как отмечалось выше, в обработчиках этого события не всегда бывает возможным предотвратить появление контекстного меню.

Объект события, передаваемый вместе с событием мыши, имеет еще пять характерных свойств, но они используются значительно реже, чем вышеперечисленные. Полный их перечень вы найдете в справочной статье Event в четвертой части книги.

В примере 17.2 демонстрируется функция drag(), которая при вызове из обработчика события «mousedown» позволяет пользователю буксировать мышью абсолютно позиционированные элементы документа. Функция drag() работает с обеими моделями событий, DOM и IE.

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

<img src=”draggable.gif"
 
 >

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

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

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

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

/**
* Drag.js: буксировка абсолютно позиционированных HTML-элементов.
*
* Этот модуль определяет единственную функцию drag(), которая должна вызываться
* из обработчика события onmousedown. Последующие события mousemove будут вызывать
* перемещение указанного элемента. Событие mouseup будет завершать буксировку.
* Эта реализация действует в обеих моделях событий, стандартной и IE.
* Использует функцию getScrollOffsets(), представленную выше в книге.
*
* Аргументы:
*
* elementToDrag: элемент, принявший событие mousedown или содержащий его элемент.
* Этот элемент должен иметь абсолютное позиционирование. Значения его свойств style.left
* и style.top будут изменяться при перемещении указателя мыши пользователем.
*
* event: объект Event, полученный обработчиком события mousedown.
**/
function drag(elementToDrag, event) {
  // Преобразовать начальные координаты указателя мыши в координаты документа
  var scroll = getScrollOffsets(): // Вспомогательная функция, объявленная
                                   // где-то в другом месте
  var startX = event.clientX + scroll.x;
  var startY = event.clientY + scroll.y;
  // Первоначальные координаты (относительно начала документа) элемента, который
  // будет перемещаться. Так как elementToDrag имеет абсолютное позиционирование,
  // предполагается, что его свойство offsetParent ссылается на тело документа,
  var origX = elementToDrag.offsetLeft;
  var origY = elementToDrag.offsetTop;
  // Найти расстояние между точкой события mousedown и верхним левым углом элемента.
  // Это расстояние будет учитываться при перемещении указателя мыши,
  var deltaX = startX - origX;
  var deltaY = startY - origY;
  // Зарегистрировать обработчики событий mousemove и mouseup,
  // которые последуют за событием mousedown,
  if (document.addEventListener) { // Стандартная модель событий
    // Зарегистрировать перехватывающие обработчики в документе
    document.addEventListener( "mousemove", moveHandler, true);
    document.addEventListener("mouseup”, upHandler, true);
  }
  else
    if (document.attachEvent) { // Модель событий IE для IE5-8
      // В модели событий IE перехват событий осуществляется вызовом
      // метода setCapture() элемента.
      elementToDrag.setCaptuге();
      elementToDrag.attachEvent("onmousemove”, moveHandleг);
      elementToDrag.attachEvent("onmouseup", upHandler);
      // Интерпретировать потерю пер’ехвата событий мыши как событие
      mouseup elementToDrag.attachEvent("onlosecapture", upHandler);
    }
  // Это событие обработано и не должно передаваться другим обработчикам
  if (event.stopPropagation)
    event.stopPropagation(); // Стандартная модель
  else
    event.cancelBubble = true; // IE
  // Предотвратить выполнение действий, предусмотренных по умолчанию,
  if (event.preventDefault)
    event.preventDefault(); // Стандартная модель
  else
    event.returnValue = false; // IE
  /**
  * Этот обработчик перехватывает события mousemove, возникающие
  * в процессе буксировки элемента. Он отвечает за перемещение элемента.
  **/
  function moveHandler(e) {
    if (!е) е = window.event; // Модель событий IE
    // Переместить элемент в позицию указателя мыши с учетом позиций
    // полос прокрутки и смещений относительно начального щелчка,
    var scroll = getScrollOffsets();
    elementToDrag.style.left = (e.clientX + scroll.x - deltaX) + "px";
    elementToDrag.style.top = (e.clientY + scroll.у - deltaY) + "px";
    // И прервать дальнейшее распространение события.
    if (е.stopPropagation)
      е.stopPropagation(); // Стандартная модель
    else
      е.cancelBubble = true; // IE
  }
  /**
  * Этот обработчик перехватывает заключительное событие mouseup,
  * которое завершает операцию буксировки.
  **/
  function upHandler(e) {
    if (!е) е = window.event; // Модель событий IE
    // Удалить перехватывающие обработчики событий,
    if (document.removeEventListener) { // Модель событий DOM
      document.removeEventListenerC'mouseup", upHandler, true);
      document.removeEventListener("mousemove", moveHandler, true);
    }
    else
      if (document.detachEvent) { // Модель событий IE 5+
        elementToDrag.detachEvent("onlosecapture", upHandler);
        elementToDrag.detachEvent("onmouseup", upHandler);
        elementToDrag.detachEvent("onmousemove", moveHandler);
        elementToDrag.releaseCapture();
      }
    // И прервать дальнейшее распространение события.
    if (е.stopPropagation)
      е.stopPropagation(); // Стандартная модель
    else
      е.cancelBubble = true; // IE
  }
}

Следующий фрагмент демонстрирует порядок использования функции drag() в HTML-файле (это упрощенная версия примера 16.2 с добавленной поддержкой буксировки):

<script src="getScrollOffsets. js"x/script> <!-- требуется функция drag()-->
<script src= "Drag. js"x/script>            <!-- определение drag() -->
<!-- Буксируемый элемент -->
<div>
  <!-- "Заголовок" окна. Обратите внимание на атрибут onmousedown. -->
  <div
              >
    Перетащи меня <!-- Содержимое заголовка -->
  </div>
  <!-- Содержимое буксируемого элемента -->
  <р>Это тест. Проверка, проверка, проверка. </р>
  <р>Тест</р>
  <р>Тест</р>
</div>

Самым важным здесь является атрибут onmousedown во вложенном элементе <div>. Обратите внимание, что в нем используется свойство this.parentNode. Это говорит о том, что перемещаться будет весь контейнерный элемент.

Оглавление книги


Генерация: 0.910. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз