снова о hover
в предыдущем посте я обещал рассказать о том, как можно с пользой применить метод .getDelayedHandlers()
— избежать лишнего мельтешения на экране и быть более терпимым к ошибкам пользователя. Выполняя обещание, опишу метод .delayedHover()
, который хотя и не применяется так широко, как «улучшенный hover», но всё равно нередко служит добрую службу.
сам по себе метод очень прост:
Element.Methods.delayedHover =
function(element, handler, delay) {
element = $(element);
var delayed = handler.getDelayedHandlers(delay);
var names = Prototype.Browser.IE
? ['mouseenter', 'mouseleave']
: ['mouseover', 'mouseout'];
element.observe(names[0], delayed.handlers.over);
element.observe(names[1], delayed.handlers.out);
return delayed;
}
на мышиные события элемента навешиваются «отложенные» обработчики, созданные при помощи .getDelayedHandlers()
. В результате исходный обработчик вызывается только тогда, когда есть уверенность, что mouseover
или mouseout
вызваны намеренно, а не из-за нетвёрдой руки пользователя. Применяется метод очевидным образом, например:
$('menu').delayedHover(function(hover){
$('submenu')[hover ? 'show' : 'hide']();
});
впрочем, интереснее рассмотреть немного более сложный случай, когда какой-то причине условное «подменю» не вложено в «главное меню». Например, если вы используете один и тот же dom-объект для отображения подсказок к разным элементам страницы. Из соображений производительности неразумно каждый раз переносить его в новое место в дереве документа, гораздо быстрее просто абсолютно позиционировать его в новом месте. Но тогда мы столкнемся с другой проблемой — при наведении мыши на подсказку на исходном объекте случится mouseout
, и подсказка исчезнет.
если взглянуть на ситуацию под другим углом, можно прийти к такому заключению: есть команда «показать подсказку», которая выполняется и при наведении на «непонятый» объект, и при наведении на саму подсказку. Есть противоположная команда, выполняющаяся при отводе мыши от объекта или подсказки. В нашем случае эти команды — delayed.handlers.over
и delayed.handlers.out
, причем они уже навешены на события исходного объекта. Осталось только назначать их событиям подсказки:
var sub = $('submenu');
$('menu').delayedHover(function(hover, delayed){
sub[hover ? 'show' : 'hide']();
var method = hover ? 'observe' : 'stopObserving';
sub[method]('mouseover', delayed.handlers.over);
sub[method]('mouseout', delayed.handlers.out);
});
вуаля! С временны́ми параметрами по умолчанию (400мс/200мс) событие mouseout
на исходном объекте не успеет произойти до того, как его отменит mouseover
на подсказке. В результате подсказка никуда не исчезнет.
сходным образом .getDelayedHandlers()
можно использовать для обнаружения даблкликов или эмуляции события input
из грядущего html5.
да, конечно, этого же результата можно добиться и простыми setTimeout/clearTimeout
, но предложенный метод мне кажется более наглядным.