2008-12-08 15 views
95

Pozwól mi opisać problem w szczegółach:Jak wyłączyć zdarzenia mouseout wyzwalane przez elementy potomne?

Chcę pokazać div bezwymiarowy pozycjonowany po najechaniu na element. To bardzo proste z jQuery i działa dobrze. Ale gdy mysz przejdzie przez jeden z elementów podrzędnych, wywoła to zdarzenie mouseout zawierającego element div. Jak powstrzymać javascript przed wyzwalaniem zdarzenia mouseout elementu zawierającego po najechaniu wskaźnikiem myszy na element potomny.

Jaki jest najlepszy i najkrótszy sposób na zrobienie tego za pomocą jQuery?

Oto uproszczony przykład, aby zilustrować, co mam na myśli:

HTML:

<a>Hover Me</a> 
<div> 
    <input>Test</input> 
    <select> 
    <option>Option 1</option> 
    <option>Option 2</option> 
    </select> 
</div> 

JavaScript/jQuery:

$('a').hover(function() { $(this).next().show() } 
       function() { $(this).next().hide() }); 
+0

[Bez wersji jQuery] (http://stackoverflow.com/q/4697758/2065702) tego pytania –

Odpowiedz

195

Pytanie jest nieco stare, ale wpadłem na to na drugi dzień.

Najprostszy sposób to zrobić z ostatnich wersji jQuery jest użycie zdarzenia mouseenter i mouseleave zamiast mouseover i mouseout.

można przetestować zachowanie szybko:

$(".myClass").on({ 
    'mouseenter':function() { console.log("enter"); }, 
    'mouseleave':function() { console.log("leave"); } 
}); 
+1

Pomógł mi rozwiązać problem związany z javascript. Używałem myszy/mouseout zamiast mouseleave z moimi słuchaczami zdarzeń! –

+1

Dla celów wyszukiwania te zachowania zdarzeń myszy są równoważne "ROLL_OVER" i "ROLL_OUT" w AS3. –

+2

Uratowałeś mi niektóre bóle głowy. Dziwne jest to, jak zawisanie na elementach potomnych wyzwala zdarzenie 'mouseout' rodzica, podczas gdy w rzeczywistości jest ono nadal wewnątrz elementu nadrzędnego. –

18

Dla uproszczenia, chciałbym tylko zreorganizować html bit do umieszczenia nowo wyświetlanej treści w elemencie, do którego przypisane jest zdarzenie mouseover:

<div id="hoverable"> 
    <a>Hover Me</a> 
    <div style="display:none;"> 
    <input>Test</input> 
    <select> 
     <option>Option 1</option> 
     <option>Option 2</option> 
    </select> 
    </div> 
</div> 

Następnie można zrobić coś takiego:

$('#hoverable').hover(function() { $(this).find("div").show(); }, 
         function() { $(this).find("div").hide(); }); 

Uwaga: Nie polecam inline css, ale to było zrobione, aby przykład łatwiejsze do strawienia.

+0

T jego jest rzeczywiście bardzo prostym i czystym rozwiązaniem. Dzięki za przypomnienie. Ale w mojej konkretnej sytuacji, która nie jest dokładnie taka, jak w pytaniu, jest to opcja. W każdym razie dzięki! –

+0

Po wypróbowaniu różnych metod opisanych przez innych tutaj w SO, wróciłem do twojej metody i sprawiłem, że zadziałało w moim przypadku. Yay! :-) –

0

Sposób, w jaki zwykle widziałem ten problem, polega na opóźnieniu o około 1/2 sekundy pomiędzy przeniesieniem myszy z elementu HoverMe. Podczas przesuwania myszy do ukrytego elementu, należy ustawić pewną zmienną, która sygnalizuje, że przesuwasz kursor nad elementem, a następnie po prostu zatrzymaj ukrytą część przed ukryciem, jeśli ta zmienna jest ustawiona. Następnie musisz dodać podobną funkcję ukrywania OnMouseOut z zawieszonego elementu, aby zniknęła po usunięciu myszy. Przepraszam, nie mogę podać ci żadnego kodu ani czegoś bardziej konkretnego, ale mam nadzieję, że to cię we właściwym kierunku.

+0

Tak idd Właśnie wprowadziłem takie rozwiązanie. To naprawdę powszechny problem. Ciekawe, jakie jest inne rozwiązanie ... Dzięki za odpowiedź! –

3

Po prostu sprawdzam, czy współrzędne myszy znajdują się poza elementem zdarzenia mouseout.

To działa, ale jest to dużo kodu za taka prosta sprawa :(

function mouseOut(e) 
{ 
    var pos = GetMousePositionInElement(e, element); 
    if (pos.x < 0 || pos.x >= element.size.X || pos.y < 0 || pos.y >= element.size.Y) 
    { 
     RealMouseOut(); 
    } 
    else 
    { 
     //Hit a child-element 
    } 
} 

Kod wyciąć dla czytelności, nie będzie działać po wyjęciu z pudełka.

+0

Hm też o tym myślałem. Czuje się trochę brudno ... ale jest bardzo prosty. –

7

Szukasz jQuery odpowiednik javascript w zapobiec pęcherzyków zdarzeń

to sprawdzić.

http://docs.jquery.com/Events/jQuery.Event#event.stopPropagation.28.29

Zasadniczo trzeba złapać zdarzenie w węzłach potomnych DOM, a tam zatrzymać ich propagacji do drzewa DOM. Innym sposobem, choć naprawdę nie jest to sugerowane (ponieważ może poważnie zagrozić istniejącym zdarzeniom na twojej stronie), jest ustawienie przechwytywania zdarzeń do określonego elementu na stronie i będzie otrzymywać wszystkie zdarzenia. Jest to użyteczne w przypadku zachowania DnD i innych, ale zdecydowanie nie w twoim przypadku.

+0

Zawsze wiedziałem, że powinien to być czysty sposób, ale nie mogę go uruchomić. Przestudiuj dokumentację lepiej. Dzięki! –

+0

działa to tak, jak powinno, nie wiem, dlaczego nie można go uruchomić. Po prostu informacja, link do dokumentu został zmieniony, nowy link to http://docs.jquery.com/Events/jQuery.Event # event.stopPropagation.28.29 – zappan

1

Zgadzam się z Ryanem.

Twój problem polega na tym, że "następny" div nie jest "dzieckiem" A. Nie ma sposobu, aby HTML lub jQuery wiedział, że twój element "a" jest związany z div div w DOM. Zawijanie ich i umieszczanie wskaźnika na opakowaniu oznacza, że ​​są one powiązane.

Należy jednak pamiętać, że jego kod nie jest zgodny z najlepszymi praktykami. Nie ustawiaj ukrytego stylu w linii na elementach; jeśli użytkownik ma kod CSS, ale nie javascript, element zostanie ukryty i nie będzie można go wyświetlić. Lepszą praktyką jest umieszczenie tej deklaracji w zdarzeniu document.ready.

+0

Całkowicie zgadzam się z umieszczeniem hide w evencie document.ready. Inline css miało właśnie przekazać pełny działający przykład w najprostszy możliwy sposób. Zmienię moją odpowiedź, aby to wyjaśnić. –

0

To stara sprawa, ale to nigdy nie staje się nieaktualne. Poprawną odpowiedzią powinna być ta podana przez bytebrite.

Chciałbym tylko wskazać różnicę między mouseover/mouseout i mouseenter/mouseleave. Możesz przeczytać świetne i pomocne wyjaśnienie here (przejdź na samo dno strony, aby zobaczyć działające demo). Podczas korzystania z mouseout zdarzenie zatrzymuje się, gdy mysz wpisze inny element, nawet jeśli jest to element podrzędny. Z drugiej strony, jeśli użyjesz mouseleave, zdarzenie nie zostanie wywołane, gdy mysz przełączy się na element podrzędny, a takie zachowanie OP chciałoby osiągnąć.

8

Yeap, chłopaki, użyj .mouseleave zamiast .mouseout:

$('div.sort-selector').mouseleave(function() { 
    $(this).hide(); 
}); 

Albo nawet używać go w połączeniu z live:

$('div.sort-selector').live('mouseleave', function() { 
    $(this).hide(); 
}); 
0

I rozwiązany ten problem dodając pointer-events: none; na moich elementów podrzędnych css

Powiązane problemy