Как узнать направление прокрутки колеса мыши

В этой коротенькой статейке, я хочу показать способ определения направления прокрутки колеса мыши. Область применения может и не такая обширная, однако я сам не раз сталкивался, где это было необходимо. Например, для создания одного "параллакс эффекта", где страница по сути не должна была скроллится, а эффект возникал только ориентируясь на то, крутит ли пользователь колесико мыши и в каком направлении. Возможно, что и вы найдете применение в своих проектах, если не сейчас, то в будущем.

function addEvent(elem, type, handler){
  if(elem.addEventListener){
    elem.addEventListener(type, handler, false);
  } else {
    elem.attachEvent('on'+type, handler);
  }
  return false;
}
function scrollDirection(){
  var weelEvt = (/Firefox/i.test(navigator.userAgent)) ? 'DOMMouseScroll' : 'mousewheel',
      el = document.body;
  addEvent(el, weelEvt, function(e){
    var evt = e.originalEvent ? e.originalEvent : e,
    delta = evt.detail ? evt.detail*(-40) : evt.wheelDelta
    console.log('Скроллим ' + (delta > 0 ? 'вверх' : 'вниз'));
  });
}
// Вешаем обработчик события загрузки документа - DOM-Ready
addEvent(window, 'load', scrollDirection);
// Для jQuery - просто вызываем функцию после загрузки DOM
/*$(function(){
  scrollDirection();
});*/

Что-то особо расписывать, я смысла не вижу. Единственное, что можно просто для себя отметить, так это то, что в данном случае "отличился" FireFox, со своим нестандартным событием "DOMMouseScroll".
Для лучшего понимания и восприятия, я решил сделать один примерчик, где предположим следующую задачу: при каждом скролле пользователя, он должен четко попадать на следующий/предыдущий раздел страницы, не проскакивая его, даже если скроллил интенсивно. При этом, будем подгружать в текущий блок соответствующий контент. Соорудим такой HTML и CSS:

<ul id="grid">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
</ul>
<div id="fake"></div>
* {
  margin: 0;
  padding: 0;
}
#grid li {
  list-style: none;
  height: 300px;
  border-bottom: 1px dotted #333;
}
#fake {height: 5000px;} /* только для того, чтоб точно был скроллбар */

Переходим к JS. Тут наша задача - отменить обычное поведение при событии прокрутки мыши (по сути - запретить пользователю прокручивание страницы вручную), вычислять, в зависимости от направление движения колеса, следующий или предыдущий блок, анимировано прокручивать до этого блока и подгружать в него необходимый контент.

$(function(){
  var flag = false, // нужен для того, чтоб предотвращать действия во время анимации
      bn = 0, // индекс текущего блока
      blocks = $('#grid li'), // все блоки
      cnt = blocks.length, // кол-во блоков
      mousewheelevt = (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel"; // событие прокрутки колеса
  blocks.eq(0).load('loadblocks.html #b0'); // сразу подгружаем контент в первый блок
  // функция определения направления прокрутки колеса
  function getDelta(e){
    var evt = e || window.event;
    evt = evt.originalEvent ? evt.originalEvent : evt;
    return delta = evt.detail ? evt.detail*(-40) : evt.wheelDelta;
  }
  // ловим событие прокрутки
  $(document).on(mousewheelevt+'.my_wheel', function(e){
    e.preventDefault(); // отменяем обычное поведение (страница не скроллится)
    if(flag) return false; // если flag == true, значит в данный момент происходит анимация
    if(getDelta(e) > 0){
      if(bn <= 0) return false; // если дошли до первого блока, то отменяем дальнейшие действия
      --bn; // если блок не первый, то высчитываем индекс предыдущего блока
    } else {
      if(bn >= cnt-1) return false; // если дошли до последнего блока, то отменяем дальнейшие действия
      ++bn; // если блок не последний, то высчитываем индекс следующего блока
    }
    flag = true; // ставим флаг, указывая, что анимация началась
    $('html, body').finish().animate({
      scrollTop : blocks.eq(bn).offset().top // прокручиваем страницу до вычисленного по индексу блока
    }, 1000, function(){
      blocks.eq(bn).load('loadblocks.html #b' + bn); // подгружаем контент для блока
      flag = false; // снимаем флаг, указывая, что анимация завершена
    });
  });
});

Расписал всё в комментариях, но осталось объяснить то, откуда подгружаются данные. В методе load(), есть возможность не только указать документ, который нужно загрузить, но и определить какой именно элемент нам будет нужен. В примере, я использовал обычный html-документ, в котором несколько элементов (по числу наших блоков) имеют ID от "b0" до "b6". Получив индекс текущего блока, мы подгружаем элемент с соответствующим id.


Пробуйте, экспериментируйте, а главное помните о том, что некоторые вещи, которые сегодня вам могут и не понадобиться - завтра могут очень сильно выручить. А если возникнут какие-то неординарные вопросы или задачи, то пишите их в этой теме или в разделе "Ваш вопрос".

Incode Pro logo

5 комментариев

Гость 12.02.2016 19:11
Не работает
Гость 12.02.2016 19:12
Вообще не работает
Гость 24.05.2016 22:04
просто подключите jQuery нормально, в файле-примере в head неправильно подключен jQuery, поэтому не работает
Incode 25.05.2016 00:17
в файле-примере в head неправильно
Вот с такими заявлениями нужно поосторожней! Сомневаюсь, что читать спецификацию вам будет интересно (RFC3986 и RFC1738), поэтому сэкономлю ваше время и предложу прочитать всего пару строк из рекомендации Google
Используйте относительные URL без указания протокола для всех остальных доменов (например, //petstore.example.com/dogs/biscuits.php) или измените ссылки сайта так, чтобы они указывали на ресурс HTTPS.
А не работало у предыдущего комментатора потому, что запускал он файл без использования сервера. Для таких случае, нужно указывать протокол.
sash 29.05.2016 16:31
А включаешь - не работает :)

не знаю, пример не качал, но функция прекрасно работает. Спасибо, пригодилась!
Ваш комментарий:
X