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

17.6. События колесика мыши

17.6. События колесика мыши

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

Существует множество проблем совместимости, связанных с событиями «mousewheel», тем не менее вполне возможно написать программный код, действующий на всех платформах. На момент написания этих строк все броузеры, кроме Firefox, поддерживали событие с именем «mousewheel». В Firefox это событие называется «DOMMouseScroll». А в проекте спецификации «DOM Level 3 Events» предложено имя «wheel» вместо «mousewheel». Вдобавок к разным именам события различаются и имена свойств объектов, передаваемых с этими различными событиями, которые определяют величину поворота колесика. Наконец, следует отметить, что существуют также важные отличия в аппаратной реализации колесиков в разных мышах. Некоторые колесики могут вращаться только в одной плоскости, назад и вперед, а некоторые (особенно в мышах компании Apple) могут вращаться также влево и вправо (в действительности такие «колесики» являются трекболами (trackball)). Стандарт «DOM Level 3» даже включает поддержку «колесиков», которые могут вращаться в трех плоскостях - по или против часовой стрелки вдобавок к вращению вперед/назад и влево/вправо.

Объект события, передаваемый обработчику события «mousewheel», имеет свойство wheelDelta, определяющее величину прокрутки колесика. Один «щелчок» колесика в направлении от пользователя обычно соответствует значению 120, а один щелчок в направлении к пользователю - значению -120. В Safari и Chrome для поддержки мышей компании Apple, имеющих трекбол вместо колесика, вращающегося в одной плоскости, вдобавок к свойству wheelDelta объект события имеет свойства wheelDeltaX и wheelDeltaY, при этом значения свойств wheelDelta и wheelDeltaY всегда совпадают.

В Firefox вместо события «mousewheel» можно обрабатывать нестандартное событие «DOMMouseScroll» и использовать свойство detail объекта события вместо wheelDelta. Однако масштаб и знак изменения свойства detail отличается от wheelDelta: чтобы получить значение, эквивалентное значению свойства wheelDelta, свойство detail нужно умножить на -40.

На момент написания этих строк проект стандарта «DOM Level 3 Events» определял стандартное событие с именем «wheel» как стандартизованную версию событий «mousewheel» и «DOMMouseScroll». Согласно спецификации, объект, передаваемый обработчику события «wheel», должен иметь свойства deltaX, deltaY и deltaZ, определяющие величину прокрутки колесика в трех плоскостях. Значения этих свойств следует умножать на -120, чтобы получить значение и знак события «mousewheel».

Для всех этих типов событий объект события напоминает объекты событий мыши: он включает координаты указателя мыши и состояние клавиш-модификаторов на клавиатуре.

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

<script src="whenReady.js"></script>
<script src="Enclose. js"x/script>
<script>
  whenReady(function() {
    enclose(document.getElementById("content"). 400,200, -200, -300);
  });
</script>
<style>div.enclosure { border: solid black 10px; margin: 10px; }</style>
<img src="testimage.jpg"/>

Для обеспечения корректной работы во всех основных броузерах в примере 17.3 выполняется проверка типа броузера (раздел 13.4.5). Пример опирается на положения спецификации «DOM Level 3 Events» и включает программный код, который будет использовать событие «wheel», когда его поддержка будет реализована в броузерах.[47]

Он также включает дополнительную проверку на будущее, чтобы не использовать событие «DOMMouseScroll», если Firefox начнет использовать событие «wheel» или «mousewheel». Обратите внимание, что пример 17.3 также является практическим примером управления геометрией элементов и использования приемов позиционирования средствами CSS, о которых рассказывалось в разделах 15.8 и 16.2.1.

Пример 17.3. Обработка событий «mousewheel»

// Заключает элемент содержимого в фрейм, или видимую область заданной ширины
// и высоты (минимальные размеры 50x50). Необязательные аргументы contentX
// и contentY определяют начальное смещение содержимого относительно кадра.
// (Их значения должны быть <= 0.) Фрейму придается обработчик события mousewheel,
// который позволяет пользователю прокручивать элемент и изменять размеры фрейма,
function enclose(content, framewidth, frameheight, contentX, contentY) {
  // Эти аргументы являются не только начальными значениями: они хранят информацию
  // о текущем состоянии, изменяются и используются обработчиком события mousewheel.
  framewidth = Math.max(framewidth, 50);
  frameheight = Math.max(frameheight, 50);
  contentX = Math.min(contentX, 0) || 0;
  contentY = Math.min(contentY, 0) || 0;
  // Создать фрейм и определить для него стили и имя класса CSS
  var frame = document.createElement("div");
  frame.className = "enclosure"; // Благодаря этому можно определять стили
                                 // в таблицах стилей
  frame.style.width = framewidth + "px"; // Установить размеры фрейма,
  frame.style.height = frameheight + "px";
  frame.style.overflow = "hidden"; // Без полос прокрутки
  frame.style.boxSizing = "border-box"; // модель border-box упрощает
  frame.style.webkitBoxSizing = "border-box"; // вычисление новых размеров
  frame.style.MozBoxSizing = "border-box"; // фрейма.
  // Добавить фрейм в документ и поместить в него элемент elt.
  content.parentNode.insertBefore(frame, content);
  frame.appendChild(content);
  // Координаты элемента относительно фрейма
  content.style.position = "relative";
  content.style.left = contentX + "px";
  content.style.top = contentY + "px";
  // Необходимо решить некоторые проблемы совместимости броузеров
  var isMacWebkit = (navigator.userAgent.index0f("Macintosh") !== -1 &&
 navigator.userAgent.index0f("WebKit") !== -1);
  var isFirefox = (navigator.userAgent.index0f("Gecko") !== -1);
  // Зарегистрировать обработчики событий mousewheel.
  frame.onwheel = wheelHandler; // Для будущих броузеров
  frame.onmousewheel = wheelHandler; // Для большинства текущих броузеров
  if (isFirefox) // Только Firefox
    frame.addEventListener("DOMMouseScroll", wheelHandler, false);
  function wheelHandler(event) {
    var e = event || window.event; // Объект события, стандартный или IE
    // Получить величину прокрутки из объекта события, проверив свойства объекта
    // события wheel, mousewheel (в обоих, 2-мерном и 1-мерном вариантах)
    // и DOMMouseScroll в Firefox.Масштабировать значение так, чтобы один «щелчок»
    // колесика соответствовал 30 пикселам. Если какой-либо из броузеров в будущем
    // будет возбуждать оба типа событий, "wheel" и "mousewheel", одно и то же
    // событие будет обрабатываться дважды. Но будем надеяться, что отмена
    // события wheel будет предотвращать возбуждение события mousewheel.
    var deltaX = e.deltaX*-30 || // событие wheel
    e.wheelDeltaX/4 || //mousewheel
                    0; // свойство не определено
    var deltaY = e.deltaY*-30 || // событие wheel
              e.wheelDeltaY/4 || // событие mousewheel в Webkit
       (e.wheelDeltaY===undefined && // Если нет 2-мерного свойства,
                  e.wheelDelta/4) || // использовать 1-мерное свойство
                    e.detail*-10 ||  // событие DOMMouseScroll в Firefox
                                  0; // свойство не определено
    // Большинство броузеров генерируют одно событие со значением 120
    // на один щелчок колесика. Однако похоже, что мыши компании Apple
    // более чувствительные, и значения свойств delta часто оказываются
    // в несколько раз больше 120, по крайней мере, для Apple Mouse.
    // Использовать прием проверки типа броузера, чтобы решить эту проблему,
    if (isMacWebkit) {
      deltaX /= ЗО;
      deltaY /= 30;
    }
    // Если мы когда-нибудь будем получать событие mousewheel или wheel в (будущих
    // версиях) Firefox, можно отказаться от обработки события DOMMouseScroll.
    if (isFirefox && e.type !== '‘DOMMouseScroll")
      frame.removeEventListener("DOMMouseScroll", wheelHandler, false);
    // Получить текущие размеры элемента содержимого
    var contentbox = content.getBoundingClientRectO;
    var contentwidth = contentbox.right - contentbox.left;
    var contentheight = contentbox.bottom - contentbox.top;
    // Если удерживается нажатой клавиша Alt, изменить размеры фрейма
    if (e.altKey) {
      if (deltaX) {
        framewidth -= deltaX; // Новая ширина фрейма, но не больше,
        framewidth = Math.min(framwidth, contentwidth); // чем ширина
        framewidth = Math.max(framewidth,50); // содержимого
        frame.style.width = framewidth + "px"; // и не меньше 50
      }
      if (deltaY) {
        frameheight -= deltaY; // To же для высоты фрейма
        frameheight = Math.min(frameheight, contentheight);
        frameheight = Math.max(frameheight-deltaY, 50);
        frame.style.height = frameheight + "px";
      }
    }
    else { // Клавиша Alt не нажата, прокрутить содержимое в фрейме
      if (deltaX) {
        // Прокручивать не больше, чем
        var minoffset = Math.min(framewidth-contentwidth, 0);
        // Сумма deltaX и contentX, но не меньше, чем minoffset
        contentX = Math.max(contentX + deltaX, minoffset);
        contentX = Math.min(contentX, 0); // или больше 0
        content.style.left = contentX + "px"; // Новое смещение
      }
      if (deltaY) {
        var minoffset = Math.min(frameheight - contentheight, 0);
        // Сумма deltaY и contentY, но не меньше, чем minoffset
        contentY = Math.max(contentY + deltaY, minoffset);
        contentY = Math.min(contentY, 0); // или больше О
        content.style.top = contentY + "px"; // Новое смещение.
      }
    }
    // He позволять всплывать этому событию. Предотвратить выполнение действий
    // по умолчанию. Это позволит предотвратить прокрутку содержимого документа
    // в окне броузера. Будем надеяться, что вызов preventDefault() для события wheel
    // также предотвратит возбуждение дублирующего события mousewheel.
    if (е.preventDefault) е.preventDefault();
    if (е.stopPropagation) е.stopPropagation();
    e.cancelBubble = true; // модель событий IE
    e.returnValue = false; // модель событий IE
    return false;
  }
}

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

Похожие страницы

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