2015-06-01 13 views
6

Jednym ze problemów ze standardowym zdarzeniem mouseout jest to, że wystrzeliwuje nie tylko wtedy, gdy kursor opuszcza obszar ekranu ograniczony zewnętrznym obwodem elementu, ale także gdy kursor unosi się nad innym elementem znajdującym się w tym obwodzie.Jak osiągnąć efekt mouseleave z absolutnie pozycjonowanymi potomkami?

Uzasadnieniem mouseleave zdarzenia jQuery jest do sygnalizowania tylko moment, gdy kursor opuści obszar ograniczony zewnętrznym obwodzie elementu.

Niestety, wydaje się, że działa tylko wtedy, gdy element "przeszkadzający" jest potomkiem "zablokowanego" elementu. Jeśli element "przeszkadzający" znajduje się w miejscu, w którym znajduje się przez bezwzględne pozycjonowanie, wówczas gdy mysz najedzie na niego, zdarzenie mouseleave na "zablokowanym" elemencie zostanie wyrzucone.

Na przykład, następujący kod HTML:

<div id="b-div"> 
    <div id="d-div"><span>d</span></div> 
</div> 
<div id="c-div"><span>c</span></div> 

... #d-div jest bona fide potomkiem #b-div, natomiast #c-div nie jest, ale, ale możemy je projektować tak, że „przeszkadza "#b-div wszystko to samo. Jest to przedstawione w this jsFiddle.

Jeśli teraz ktoś definiuje następujące wydarzenia na #b-div:

$('#b-div').bind({ 
    mouseenter: function() { 
     $(this).addClass('outlined'); 
    }, 
    mouseleave: function() { 
     $(this).removeClass('outlined'); 
    } 
}); 

... następnie unosi kursor w zewnętrznym obwodzie #b-div „s powoduje niebieski zarys pojawiać się nad tym obwodzie, chyba mysz jest ponad #c-div.

Czy istnieje sposób, aby uzyskać ten sam efekt z #b-div i #c-div jako mouseleave osiąga z #b-div i #d-div?

EDYCJA: Naprawiłem przykład pokazany w jsFiddle. Oryginalna wersja tego przykładu pokazała niereprezentatywny specjalny przypadek, w którym cały element przeszkadzający pokrywa się z zablokowanym elementem. W tym szczególnym przypadku, pożądany efekt może być symulowany , symulowany poprzez zdefiniowanie tych samych zdarzeń zarówno na przeszkadzających, jak i zatkanych elementach, skutkiem czego, w rezultacie, obrócenie elementu przeszkadzającego w łatę zatkanego elementu. To nie zadziała, gdy element przeszkadzający nie jest w pełni zawarty w zewnętrznym obwodzie przeszkadzanego elementu (jak pokazano w poprawionym jsFiddle). Mówiąc bardziej ogólnie, każde rozwiązanie oparte na wykorzystaniu zdarzenia mouseover na przeszkadzającym elemencie zakończy się niepowodzeniem, ponieważ problem polega na zapobieganiu (lub renderowaniu nieskuteczności) fałszywego mouseleave na zablokowanym elemencie.

+0

Masz na myśli to -> ** https: //jsfiddle.net/adeneo/q1Lgzr4c/1/** – adeneo

+0

@adeneo: okazuje się, że mój oryginalny przykład ilustruje nieco niereprezentatywny przypadek specjalny; Zaktualizowałem przykład, aby to poprawić. Przepraszam za to. – kjo

+0

To, co prawie działa, polega na sprawdzeniu "e.relatedTarget" https://jsfiddle.net/p5yf0dcs/2/ Problem polega na tym, że teraz nie stracisz podświetlenia podczas budowania z "b-div" –

Odpowiedz

7

to to, na podstawie początkowego postu, w którym #c-div został całkowicie zawarty w #b-div:

$('#b-div, #c-div').on({ 
    mouseenter: function (ev) { 
    $('#b-div').addClass('outlined'); 
    }, 
    mouseleave: function (ev) { 
    $('#b-div').removeClass('outlined'); 
    } 
}); 

Fiddle 1


Od #c-div nie zawsze może być zawarta całkowicie wewnątrz #b-div, można skorzystać z istniejącego kodu jeśli dodasz ten styl:

#c-div { 
    pointer-events: none; 
} 

Ale to sprawi, że t niemożliwe do interakcji z #c-div za pomocą myszy.

Fiddle 2


Jeśli zrobić potrzebę interakcji z #c-div, i to nie jest całkowicie w ciągu #b-div, można użyć Element.getBoundingClientRect tak:

$('#b-div, #c-div').on('mousemove mouseleave', 
    function(ev) { 
    var br= $('#b-div')[0].getBoundingClientRect(); 
    $('#b-div').toggleClass(
     'outlined', 
     ev.pageX > br.left && ev.pageX < br.left+br.width && 
     ev.pageY > br.top && ev.pageY < br.top +br.height 
    ) 
    } 
); 

Fiddle 3

+0

Po obejrzeniu Twojego rozwiązania zdałem sobie sprawę, że mój oryginalny przykład był poważnie wadliwy na . Naprawiłem to teraz. Ufam, że z nową wersją będzie bardziej zrozumiałe, dlaczego proponowane rozwiązania, takie jak proponowane, nie będą działać ogólnie (zawisanie nad częściami elementu blokującego , które nie pokrywają się z blokującym elementem , nie powinno powodować event mouseenter'). Przepraszam za brak jasności w moim oryginalnym wpisie. – kjo

+1

Możesz dodać 'wskaźnik-zdarzenia: brak' do stylu' # c-div' - * chyba że * ma zawartość wymaganą do interakcji za pomocą myszy. –

+0

@kjo Czy nadal potrzebujesz odpowiedzi lub znalazłeś rozwiązanie problemu – MaxZoom

0

Jeśli nie możesz skorzystać z sugestii Richa: pointer-events: none (może potrzebujesz support IE 10 lub potrzebujesz interakcji z pozycjonowanym div), możesz ręcznie sprawdzić, czy zdarzenie nie będzie miało wartości #c-div przy użyciu relatedTarget.

Musisz jednak również sprawdzić, czy mouseleave z #c-div nie przejdzie na #b-div.

$('#b-div').bind({ 
 
    mouseenter: function() { 
 
     $(this).addClass('outlined'); 
 
    }, 
 
    mouseleave: function (e) { 
 
     if (e.relatedTarget.id == 'c-div' || $.contains(document.getElementById('c-div'), e.relatedTarget)) { 
 
      return; 
 
     } 
 
     $(this).removeClass('outlined'); 
 
    } 
 
}); 
 

 
$('#c-div').bind({ 
 
    mouseleave: function (e) { 
 
     if (e.relatedTarget.id == 'b-div' || $.contains(document.getElementById('b-div'), e.relatedTarget)) { 
 
      return; 
 
     } 
 
     $('#b-div').removeClass('outlined'); 
 
    } 
 
});
#a-div { 
 
    position: relative; 
 
    margin: 20px; 
 
} 
 
#b-div { 
 
    height: 100px; 
 
    width: 100px; 
 
    background-color: #555; 
 
    padding: 50px; 
 
} 
 
#c-div { 
 
    position: absolute; 
 
    height: 50px; 
 
    width: 200px; 
 
    top: 100px; 
 
    left: 100px; 
 
    background-color: #999; 
 
} 
 
#d-div { 
 
    height: 50px; 
 
    width: 50px; 
 
    background-color: #ddd; 
 
    text-align: center; 
 
} 
 
#c-div span { 
 
    margin: 21.5px; 
 
    line-height: 50px; 
 
} 
 
#d-div span { 
 
    margin: auto; 
 
    line-height: 50px; 
 
} 
 
.outlined { 
 
    outline: 10px solid steelblue; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="a-div"> 
 
    <div id="b-div"><div id="d-div"><span>d</span></div></div> 
 
    <div id="c-div"><span>c</span></div> 
 
</div>

+1

To nie podświetla '# b-div' jeśli początkowo wisisz' # c-div', więc ja wykładam Uważa, że ​​całkowicie spełnia wymagania PO. –

Powiązane problemy