Zapobiega onmouseout, gdy unosi się element potomny nadrzędnego absolutnego div bez jQuery

Mam problem z funkcją onmouseout w absolutnym pozycjonowanym div. Gdy mysz uderzy w element potomny w div, zostanie wywołane zdarzenie mouseout, ale nie chcę, aby zostało uruchomione, dopóki mysz nie znajdzie się poza rodzicem, absolutnym div.

Jak zapobiec wywołaniu zdarzenia mouseout, gdy uderzy ono w element potomny bez jquery.

Wiem, że to ma coś wspólnego z bulgotaniem zdarzeń, ale nie mam szczęścia, aby dowiedzieć się, jak to rozwiązać.

Znalazłem podobny post tutaj: Jak wyłączyć zdarzenia mouseout wyzwalane przez elementy potomne?

Jednak To rozwiązanie używa jQuery.

Author: Cœur, 2011-01-15

17 answers

function onMouseOut(event) {
        //this is the original element the event handler was assigned to
        var e = event.toElement || event.relatedTarget;
        if (e.parentNode == this || e == this) {
           return;
        }
    alert('MouseOut');
    // handle mouse event here!
}



document.getElementById('parent').addEventListener('mouseout',onMouseOut,true);

Zrobiłem szybkie demo JsFiddle, z wszystkimi CSS i HTML potrzebne, sprawdź to...

EDIT FIXED link for cross-browser support http://jsfiddle.net/RH3tA/9/

Zauważ , że to sprawdza tylko najbliższego rodzica, jeśli rodzic div miał zagnieżdżone dzieci, to musisz jakoś przejść przez elementy parents szukając "elementu oryginalnego"

EDIT przykład dla zagnieżdżonych dzieci

EDIT Fixed for miejmy nadzieję, że cross-browser

function makeMouseOutFn(elem){
    var list = traverseChildren(elem);
    return function onMouseOut(event) {
        var e = event.toElement || event.relatedTarget;
        if (!!~list.indexOf(e)) {
            return;
        }
        alert('MouseOut');
        // handle mouse event here!
    };
}

//using closure to cache all child elements
var parent = document.getElementById("parent");
parent.addEventListener('mouseout',makeMouseOutFn(parent),true);

//quick and dirty DFS children traversal, 
function traverseChildren(elem){
    var children = [];
    var q = [];
    q.push(elem);
    while (q.length > 0) {
      var elem = q.pop();
      children.push(elem);
      pushAll(elem.children);
    }
    function pushAll(elemArray){
      for(var i=0; i < elemArray.length; i++) {
        q.push(elemArray[i]);
      }
    }
    return children;
}

I NowyJSFiddle, EDIT updated link

 86
Author: Amjad Masad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-05 14:54:37

Dla prostszego czystego rozwiązania CSS , które działa w niektórych przypadkach (IE11 lub nowszy), można usunąć pointer-events ustawiając je na none

.parent * {
     pointer-events: none;
}
 72
Author: Zach Saucier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-23 02:41:51

Użyj onmouseleave.

Lub w jQuery użyj mouseleave()

To jest dokładnie to, czego szukasz. Przykład:
<div class="outer" onmouseleave="yourFunction()">
    <div class="inner">
    </div>
</div>

Lub w jQuery:

$(".outer").mouseleave(function(){
    //your code here
});

Przykładem jest tutaj .

 66
Author: PHPWannaBePro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-26 14:35:36

Oto bardziej eleganckie rozwiązanie oparte na tym, co przyszło poniżej. odpowiada za zdarzenia z więcej niż jednego poziomu dzieci. Dotyczy to również problemów z przeglądarką.

function onMouseOut(this, event) {
//this is the original element the event handler was assigned to
   var e = event.toElement || event.relatedTarget;

//check for all children levels (checking from bottom up)
while(e && e.parentNode && e.parentNode != window) {
    if (e.parentNode == this||  e == this) {
        if(e.preventDefault) e.preventDefault();
        return false;
    }
    e = e.parentNode;
}

//Do something u need here
}

document.getElementById('parent').addEventListener('mouseout',onMouseOut,true);
 26
Author: Sam-Elie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-08 10:03:22

Jeśli używasz jQuery, możesz również użyć funkcji "mouseleave", która zajmuje się tym wszystkim za Ciebie.

$('#thetargetdiv').mouseenter(do_something);
$('#thetargetdiv').mouseleave(do_something_else);

Do_something wystrzeli, gdy mysz wejdzie do celu lub któregokolwiek z jej dzieci, do_something_else wystrzeli tylko wtedy, gdy mysz opuści cel i którekolwiek z jej dzieci.

 12
Author: Jamie Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-06 23:33:50

Dzięki Amjadowi Masadowi, który mnie zainspirował.

Mam następujące rozwiązanie, które wydaje się działać w IE9, FF i Chrome i Kod jest dość krótki (bez skomplikowanego zamknięcia i poprzecznych rzeczy potomnych):

    DIV.onmouseout=function(e){
        // check and loop relatedTarget.parentNode
        // ignore event triggered mouse overing any child element or leaving itself
        var obj=e.relatedTarget;
        while(obj!=null){
            if(obj==this){
                return;
            }
            obj=obj.parentNode;
        }
        // now perform the actual action you want to do only when mouse is leaving the DIV
    }
 11
Author: Lawrence Mok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-02 04:40:48

Myślę, że Quirksmode ma wszystkie odpowiedzi, których potrzebujesz (różne zachowania bulgotania przeglądarek i zdarzenia mouseenter/mouseleave), ale myślę, że najczęstszym wnioskiem do tego zdarzenia bubbling mess jest użycie frameworka jak JQuery lub Mootools (który ma mouseenter i mouseleave zdarzenia, które są dokładnie tym, co się wydarzy).

Zobacz, jak to robią, jeśli chcesz, zrób to sam
lub możesz utwórz własną wersję Mootools "lean mean" z tylko częścią zdarzenia (i jego zależnościami).

 7
Author: Ruben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-15 03:34:08

Try mouseleave()

Przykład:

<div id="parent" mouseleave="function">
   <div id="child">

   </div>
</div>

;)

 7
Author: Jean-Philippe Ménard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-18 18:41:00

Znalazłem bardzo proste rozwiązanie,

Wystarczy użyć zdarzenia onmouseleave= " myfunc ()"niż zdarzenia onmousout=" myfunc () "

W moim kodzie zadziałało!!

Przykład:

<html>
<head>
<script type="text/javascript">
   function myFunc(){
      document.getElementById('hide_div').style.display = 'none';
   }
   function ShowFunc(){
      document.getElementById('hide_div').style.display = 'block';
   }
</script>
</head>
<body>
<div onmouseleave="myFunc()" style='border:double;width:50%;height:50%;position:absolute;top:25%;left:25%;'>
   Hover mouse here
   <div id='child_div' style='border:solid;width:25%;height:25%;position:absolute;top:10%;left:10%;'>
      CHILD <br/> It doesn't fires if you hover mouse over this child_div
   </div>
</div>
<div id="hide_div" >TEXT</div>
<a href='#' onclick="ShowFunc()">Show "TEXT"</a>
</body>
</html>

Ten sam przykład z funkcją mouseout:

<html>
<head>
<script type="text/javascript">
   function myFunc(){
      document.getElementById('hide_div').style.display = 'none';
   }
   function ShowFunc(){
      document.getElementById('hide_div').style.display = 'block';
   }
</script>
</head>
<body>
<div onmouseout="myFunc()" style='border:double;width:50%;height:50%;position:absolute;top:25%;left:25%;'>
   Hover mouse here
   <div id='child_div' style='border:solid;width:25%;height:25%;position:absolute;top:10%;left:10%;'>
      CHILD <br/> It fires if you hover mouse over this child_div
   </div>
</div>
<div id="hide_div">TEXT</div>
<a href='#' onclick="ShowFunc()">Show "TEXT"</a>
</body>
</html>

Mam nadzieję, że pomoże:)

 5
Author: Arminius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-26 13:03:59

Są dwa sposoby, by sobie z tym poradzić.

1) Sprawdź Zdarzenie.docelowy wynik w wywołaniu zwrotnym, aby sprawdzić, czy pasuje do rodzica div

var g_ParentDiv;

function OnMouseOut(event) {
    if (event.target != g_ParentDiv) {
        return;
    }
    // handle mouse event here!
};


window.onload = function() {
    g_ParentDiv = document.getElementById("parentdiv");
    g_ParentDiv.onmouseout = OnMouseOut;
};

<div id="parentdiv">
    <img src="childimage.jpg" id="childimg" />
</div>

2) lub użyj przechwytywania zdarzeń i wywoływania zdarzeń.stopropagacja w funkcji callback

var g_ParentDiv;

function OnMouseOut(event) {

    event.stopPropagation(); // don't let the event recurse into children

    // handle mouse event here!
};


window.onload = function() {
    g_ParentDiv = document.getElementById("parentdiv");
    g_ParentDiv.addEventListener("mouseout", OnMouseOut, true); // pass true to enable event capturing so parent gets event callback before children
};

<div id="parentdiv">
    <img src="childimage.jpg" id="childimg" />
</div>
 1
Author: selbie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-15 06:56:02

I make it work like a charm with this:

function HideLayer(theEvent){
 var MyDiv=document.getElementById('MyDiv');
 if(MyDiv==(!theEvent?window.event:theEvent.target)){
  MyDiv.style.display='none';
 }
}

Ah, a MyDiv tag jest taki:

<div id="MyDiv" onmouseout="JavaScript: HideLayer(event);">
 <!-- Here whatever divs, inputs, links, images, anything you want... -->
<div>

W ten sposób, gdy onmouseout idzie do dziecka, dziadka itp... style.display='none' nie jest wykonywany; ale gdy onmouseout wychodzi z MyDiv, uruchamia się.

Więc nie ma potrzeby zatrzymywania propagacji, używania timerów itp...

Dzięki za przykłady, mógłbym z nich zrobić ten kod.

Mam nadzieję, że to komuś pomoże.

Również można poprawić w ten sposób:

function HideLayer(theLayer,theEvent){
 if(theLayer==(!theEvent?window.event:theEvent.target)){
  theLayer.style.display='none';
 }
}

A potem znaczniki Div tak:

<div onmouseout="JavaScript: HideLayer(this,event);">
 <!-- Here whatever divs, inputs, links, images, anything you want... -->
<div>

Więc bardziej ogólne, nie tylko dla jednego div I nie ma potrzeby dodawania id="..." na każdej warstwie.

 1
Author: z666zz666z,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-28 11:23:38

Sprawdzam przesunięcie elementu oryginalnego, aby uzyskać współrzędne strony granic elementu, a następnie upewnij się, że akcja mouseout jest uruchamiana tylko wtedy, gdy mouseout jest poza tymi granicami. Brudne, ale działa.

$(el).live('mouseout', function(event){
    while(checkPosition(this, event)){
        console.log("mouseovering including children")
    }
    console.log("moused out of the whole")
})

var checkPosition = function(el, event){
    var position = $(el).offset()
    var height = $(el).height()
    var width = $(el).width()
    if (event.pageY > position.top 
|| event.pageY < (position.top + height) 
|| event.pageX > position.left 
|| event.pageX < (position.left + width)){
    return true
}
}
 0
Author: saranicole,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-25 15:08:46
var elem = $('#some-id');
elem.mouseover(function () {
   // Some code here
}).mouseout(function (event) {
   var e = event.toElement || event.relatedTarget;
   if (elem.has(e).length > 0) return;

   // Some code here
});
 0
Author: Michael Vaganov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-02 15:49:06

Jeśli dodałeś (lub masz) klasę CSS lub id do elementu nadrzędnego, możesz zrobić coś takiego:

<div id="parent">
  <div>
  </div>
</div>

JavaScript:
document.getElementById("parent").onmouseout = function(e) {
  e = e ? e : window.event //For IE
  if(e.target.id == "parent") {
    //Do your stuff
  }
}

Więc rzeczy są wykonywane tylko wtedy, gdy zdarzenie znajduje się na nadrzędnym div.

 0
Author: Karthik Palaniappan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-13 19:19:09

Chciałam się z Tobą czymś podzielić.
Mam problemy z ng-mouseenter i ng-mouseleave wydarzeniami.

Studium przypadku:

Stworzyłem pływające menu nawigacyjne, które przełącza się, gdy kursor znajduje się nad ikoną.
To menu było na górze każdej strony.

  • aby obsłużyć pokaż/ukryj w menu, przełączam klasę.
    ng-class="{down: vm.isHover}"
  • aby przełączyć vm.isHover, używam zdarzeń myszy ng.
    ng-mouseenter="vm.isHover = true"
    ng-mouseleave="vm.isHover = false"

Dla teraz wszystko było w porządku i działało zgodnie z oczekiwaniami.
Rozwiązanie jest czyste i proste.

Problem przychodzący:

W konkretnym widoku mam listę elementów.
Dodałem panel akcji, gdy kursor znajduje się nad elementem listy.
Użyłem tego samego kodu jak powyżej do obsługi zachowania.

Problem:

Zorientowałem się, że gdy mój kursor znajduje się na pływającym menu nawigacyjnym, a także na górze elementu, jest konflikt między sobą.
Pojawił się panel akcji, a nawigacja pływająca została ukryta.

Chodzi o to, że nawet jeśli kursor znajduje się nad pływającym menu nawigacyjnym, aktywowany jest element listy ng-mouseenter.
Nie ma to dla mnie sensu, ponieważ spodziewałbym się automatycznego przerwania zdarzeń propagacji myszy.
Muszę powiedzieć, że byłem rozczarowany i spędziłem trochę czasu, aby dowiedzieć się, że problem.

Pierwsze myśli:

Próbowałem użyj tych :

  • $event.stopPropagation()
  • $event.stopImmediatePropagation()

Połączyłem wiele zdarzeń ng pointer (mousemove, mouveover, ...), ale żaden mi nie pomógł.

Rozwiązanie CSS:

Znalazłem rozwiązanie z prostą właściwością css, której używam coraz częściej:

pointer-events: none;

Zasadniczo używam go w ten sposób (na mojej liście elementów):

ng-style="{'pointer-events': vm.isHover ? 'none' : ''}"

Z tym trudnym, zdarzenia ng-mouse nie będą już uruchamiane, a moje pływające menu nawigacyjne nie będzie już uruchamiane Zamknij się, gdy kursor znajduje się nad nim i nad elementem z listy.

Aby przejść dalej:

Jak można się spodziewać, To rozwiązanie działa, ale nie podoba mi się to.
Nie kontrolujemy naszych wydarzeń i jest źle.
Dodatkowo musisz mieć dostęp do zakresu vm.isHover, aby to osiągnąć i może to nie być możliwe Lub możliwe, ale brudne w jakiś czy inny sposób.
Mogę zrobić skrzypce, jeśli ktoś chce spojrzeć.

Niemniej jednak, nie mam innego rozwiązanie...
To długa historia i nie mogę dać ci ziemniaka, więc wybacz mi, przyjacielu.
W każdym razie, pointer-events: none jest życie, więc pamiętaj o nim.

 0
Author: C0ZEN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-01 21:48:54

Jeśli masz dostęp do elementu, do którego zdarzenie jest dołączone wewnątrz metody mouseout, możesz użyć contains(), aby sprawdzić, czy event.relatedTarget jest elementem potomnym, czy nie.

Ponieważ event.relatedTarget jest elementem, do którego przeszła mysz, jeśli nie jest elementem potomnym, to został on usunięty.

div.onmouseout = function (event) {
    if (!div.contains(event.relatedTarget)) {
        // moused out of div
    }
}
 0
Author: spaceman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-14 16:10:41

Chociaż rozwiązanie , o którym mowa, używa jquery, mouseenter i mouseleave są natywnymi zdarzeniami dom, więc możesz używać ich bez jquery.

 0
Author: Mohammed Essehemy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-26 22:29:25