Вернуться к уроку

Подсказка при замедлении над элементом

важность: 5

Нужно написать функцию, которая показывает подсказку при наведении на элемент, но не при быстром проходе над ним.

То есть, если посетитель именно навёл курсор мыши на элемент и почти остановился – подсказку показать, а если быстро провёл над ним, то не надо, зачем излишнее мигание?

Технически – можно измерять скорость движения мыши над элементом, если она маленькая, то считаем, что это «наведение на элемент» (показать подсказку), если большая – «быстрый проход мимо элемента» (не показывать).

Реализуйте это через универсальный объект new HoverIntent(options), с параметрами options:

  • elem – элемент, наведение на который нужно отслеживать.
  • over – функция-обработчик наведения на элемент.
  • out – функция-обработчик ухода с элемента (если было наведение).

Пример использования такого объекта для подсказки:

// образец подсказки
var tooltip = document.createElement('div');
tooltip.className = "tooltip";
tooltip.innerHTML = "Подсказка";

// при "наведении на элемент" показать подсказку
new HoverIntent({
  elem: elem,
  over: function() {
    tooltip.style.left = this.getBoundingClientRect().left + 'px';
    tooltip.style.top = this.getBoundingClientRect().bottom + 5 + 'px';
    document.body.appendChild(tooltip);
  },
  out: function() {
    document.body.removeChild(tooltip);
  }
});

Демо этого кода:

Если провести мышкой над «часиками» быстро, то ничего не будет, а если медленно или остановиться на них, то появится подсказка.

Обратите внимание – подсказка не «мигает» при проходе мыши внутри «часиков», по подэлементам.

Открыть песочницу с тестами для задачи.

Будем замерять скорость движения курсора.

Для этого можно запустить setInterval, который каждые 100 мс (или другой интервал) будет сравнивать текущие координаты курсора с предыдущими и, если расстояние пройдено маленькое, считаем, что посетитель «навёл указатель на элемент», вызвать options.over.

В браузере нет способа «просто получить» текущие координаты. Это может сделать обработчик события, в данном случае mousemove. Поэтому нужно будет поставить обработчик на mousemove и при каждом движении запоминать текущие координаты, чтобы setInterval мог раз в 100 мс сравнивать их.

Имеет смысл начинать анализ координат и отслеживание mousemove при заходе на элемент, а заканчивать – при выходе с него.

Чтобы точно отловить момент входа и выхода, без учёта подэлементов (во избежание мигания), можно использовать mouseenter/mouseleave.

В решении, предложенном ниже, однако, используется mouseover/mouseout, так как это позволит легко «прикрутить» к такому объекту делегирование, если потребуется. А, чтобы не было лишних срабатываний, лишние переходы отфильтровываются.

При этом при обнаружении «наведения на элемент» это запоминается в переменной isHover и вызывается options.over, а затем, при выходе с элемента, если было «наведение», вызывается options.out.

Открыть решение с тестами в песочнице.