"Умная" подсказка
Напишите функцию, которая показывает подсказку над элементом только в случае, когда пользователь передвигает мышь на него, но не через него.
Другими словами, если пользователь подвинул курсор на элементе и остановился – показывать подсказку. А если он просто быстро провёл курсором по элементу, то не надо ничего показывать. Кому понравится лишнее мелькание?
Технически, мы можем измерять скорость прохода курсора мыши над элементом, и если она низкая, то можно посчитать, что пользователь остановил курсор над элементом, и показать ему подсказку. А если скорость высокая, то тогда не показывать.
Создайте для этого универсальный объект new HoverIntent(options)
.
Его настройки options
:
elem
– отслеживаемый элемент.over
– функция, вызываемая, при заходе на элемент, считаем что заход – это когда курсор медленно двигается или остановился над элементом.out
– функция, вызываемая при уходе курсора с элемента (если был заход).
Пример использования такого объекта для показа подсказки:
// пример подсказки
let tooltip = document.createElement('div');
tooltip.className = "tooltip";
tooltip.innerHTML = "Tooltip";
// объект будет отслеживать движение мыши и вызывать функции over/out
new HoverIntent({
elem,
over() {
tooltip.style.left = elem.getBoundingClientRect().left + 'px';
tooltip.style.top = elem.getBoundingClientRect().bottom + 5 + 'px';
document.body.append(tooltip);
},
out() {
tooltip.remove();
}
});
Демо:
Если двигать курсор над «часами» быстро, то ничего не произойдёт, а если вы замедлите движение курсора над элементом или остановите его, то будет показана подсказка.
Обратите внимание: подсказка не должна пропадать (мигать), когда курсор переходит между дочерними элементами часов.
Алгоритм выглядит просто:
- Назначаем обработчики
onmouseover/out
на элементе. Также можно было бы использоватьonmouseenter/leave
, но они менее универсальны и не сработают с делегированием. - Когда курсор переходит на элемент, начинаем измерять скорость его движения, используя
mousemove
. - Если скорость низкая, то вызываем
over
. - Когда мы выходим из элемента, если запускали
over
, вызываемout
.
Но как измерить скорость?
Первая идея может быть такой: запускать нашу функцию каждые 100ms
и находить разницу между прежними и текущими координатами курсора. Если она мала, то значит и скорость низкая.
К сожалению, в JavaScript нет возможности получать текущие координаты мыши. Не существует функции типа получитьТекущиеКоординатыМыши()
.
Единственный путь – это слушать события мыши, например mousemove
, и координаты брать из объекта события.
Так что поставим обработчик на mousemove
, чтобы отслеживать координаты и запоминать их. И будем сравнивать результаты каждые 100ms
.
P.S. Обратите внимание: тесты для решения этой задачи используют dispatchEvent
, чтобы проверить, что подсказка работает корректно.