[jQuery] Dlaczego nie należy używać .hover() w jQuery?

Data dodania wpisu: 28-05-2010

Zacznijmy od tego, że hover() nie jest prawidłowym eventem na obiektach DOMDocument, tylko pseudoklasą. Dlaczego sprawia problemy w stylu blokady odpalania eventów, które naśladuje (czyli mouseover i mouseleave). Tworząc skrótowy handler w postaci hovera na obiekcie, można spowodować blokadę odpalenia eventu mouseleave w przypadku szybkiej akcji wskazania i usunięcia wskaźnika myszki ze zbindowanego elementu. Taki "błąd" objawia się np. w przypadku bibliotek z Tooltipami (balonikami) pisanych dla starszych wersji jQuery. Dlatego zamiast stosowania:

$(element).hover(function() {
   // akcja
}, function() {
   // akcja
});

po pierwsze należy przerzucić się na wzbogacone o nowe eventy jQuery (aktualna wersja stabilna - 1.4.3), a następnie nauczyć się wykorzystywać metodę .delegate(), która inicjuje w prawidłowy sposób event mouseover i mouseleave w jednej regule - piękny bajer wbudowany w nową wersję tego frameworka - wcześniej był to osobny plugin:) Poniżej kawałek kodu, który w prawidłowy sposób inicjuje akcję na obiekcie dokumentu HTML z wykorzystaniem tej własnie metody:

$("body").delegate('a','mouseover mouseleave', function(e){
    if (e.type == 'mouseover') {
        $(this).css('zoom','2');
    } else {
        $(this).css('zoom','1');
    }
});

Powyższy event sprawi, że po wskazaniu na link, powiększy się on dwukrotnie - wersja dla ślepych, hehe. Po usunięciu wskaźnika myszki z linku, wróci zaś do swojego naturalnego rozmiaru. I problem z działającym niepoprawnie hoverem poszedł w pierony:)


EDIT:

Oczywiście, jeśli ktoś stosuje starsze wersje jQuery niż wersja 1.4.*, można stosować albo eventy mouseover / mouseenter / mouseout / mouseleave, czy też nieszczesny hover, z tą różnicą, że przed właściwą akcją (np. event .animate()) trzeba dorzucić event .stop() z odpowiednimi parametrami (w 95% sytuacji wystarczy stop(true,true), który w przypadku niezakończenia wykonywania eventu na obiekcie, wraca do stanu zerowego.

Przykład - rozwijalne menu po wskazaniu na element - matkę, rozwinie listę subelementów wskazanej pozycji menu:

$(".menu-item").hover(function() {
   $(this).find('ul.submenu').stop(true,true).addClass('hovered').slideToggle('medium');
}, function() {
   $(this).find('ul.submenu').stop(true,true).removeClass('hovered').slideToggle('medium');
});

Mimo wszystko - zalecam przerzucić się na nową wersję jQuery i wykorzystanie jej możliwości, które nie dość, że są funkcjonalne w niemal każdej przeglądarce, to są lepiej zoptymalizowane pod kątem wydajności nawet w tych kIEpskich przeglądarkach.

Komentarze

Fajny wpis, jednak przy 'delegate'/'live' czasami występują błędy przy interpretacji bloków, na które chce się jakiś efekt nałożyć. Sam też zachęcam do używania 'delegate' chociażby jako zamiennika dla 'hover', ale radzę być czujnym i sprawdzać, czy wszystko jest OK pod chociażby FF3.6.
Comments closed...