Предотвращение onmouseout при наведении на дочерний элемент родительского абсолютного div без jQuery

у меня проблемы с onmouseout функция в абсолютном позиционном div. Когда мышь попадает в дочерний элемент в div, событие mouseout срабатывает, но я не хочу, чтобы он срабатывал, пока мышь не выйдет из родительского, абсолютного div.

Как я могу запретить mouseout событие от запуска, когда оно попадает в дочерний элемент без jquery.

Я знаю, что это имеет какое-то отношение к пузырящемуся событию, но мне не повезло узнать, как это сделать.

Я нашел аналогичный пост здесь:Как отключить события mouseout, вызванные дочерними элементами?

однако это решение использует jQuery.

17 ответов


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);

Я сделал быструю демонстрацию jsfiddle, со всеми необходимыми CSS и HTML, проверьте это...

редактировать исправлена ссылка для поддержки кросс-браузераhttp://jsfiddle.net/RH3tA/9/

Примечание что это проверяет только непосредственный родитель, если родительский div имел вложенных детей, то вы должны каким-то образом пройти через элементы родителей, ищущих "исходный элемент"

редактировать пример вложенных дети!--3-->

редактировать исправлено для кросс-браузера

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;
}

и новая JSFiddle, редактировать обновили ссылку


для более простого чистого решения CSS это работает в некоторых случаях (IE11 или новее), можно удалить детей pointer-events установив их в none

.parent * {
     pointer-events: none;
}

использовать onmouseleave.

или, в jQuery, используйте mouseleave()

это именно то, что вы ищете. Пример:

<div class="outer" onmouseleave="yourFunction()">
    <div class="inner">
    </div>
</div>

или, в jQuery:

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

пример здесь.


вот более элегантное решение, основанное на том, что было ниже. это объясняет событие, пузырящееся из более чем одного уровня детей. Это также кросс-браузер вопросы.

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);

Если вы используете jQuery, вы также можете использовать функцию "mouseleave", которая занимается всем этим для вас.

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

do_something будет срабатывать, когда мышь входит в thetargetdiv или любой из его детей, do_something_else будет срабатывать только тогда, когда мышь покидает thetargetdiv и любой из его детей.


благодаря Амджаду Масаду, который вдохновил меня.

У меня есть следующее решение, которое, кажется, работает в IE9, FF и Chrome, и код довольно короткий (без сложного закрытия и поперечных дочерних вещей):

    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
    }

Я думаю Quirksmode имеет все ответы, которые вам нужны (различные браузеры пузырящееся поведение и mouseenter / mouseleave события), но я думаю, что самый распространенный вывод к этому событию пузырящийся беспорядок is использование фреймворка, такого как JQuery или Mootools (который имеет события мыши: mouseenter и mouseleave события, которые именно то, что вы интуитивно произойдет).

посмотрите, как они это делают, если хотите, сделайте он сам
или вы можете создать свой собственный "lean mean" версия Mootools только с частью события (и его зависимостями).


попробовать mouseleave()

пример :

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

   </div>
</div>

;)


Я нашел очень простое решение,

просто используйте событие onmouseleave= " myfunc ()", чем событие onmousout=" myfunc ()"

в моем коде это сработало!!

пример:

<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>

тот же пример с функцией 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>

надеюсь, что это помогает :)


есть два способа справиться с этим.

1) Проверьте событие.целевой результат в обратном вызове, чтобы увидеть, соответствует ли он вашему родительскому 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)или используйте захват события и вызов события.это происходит в функции обратного вызова

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>

Я заставляю его работать как шарм с этим:

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

а, а MyDiv тег выглядит так:

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

таким образом, при onmouseout идет к ребенку, внуку и т. д... the style.display='none' не выполняется; но когда onmouseout выходит из MyDiv, он запускается.

поэтому нет необходимости останавливать распространение, использовать таймеры и т. д...

Спасибо за примеры, я могу сделать этот код из них.

надеюсь, это кому-то поможет.

также можно улучшить вот так:

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

а затем DIVs теги, как это:

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

так что более общий, не только для одного div и не нужно добавлять id="..." на каждый слой.


Я проверяю смещение исходного элемента, чтобы получить координаты страницы границ элемента, затем убедитесь, что действие mouseout запускается только тогда, когда mouseout выходит за эти границы. Грязно, но работает.

$(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
}
}

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
});

Если вы добавили (или имеете) класс CSS или id к родительскому элементу, то вы можете сделать что-то вроде этого:

<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
  }
}

поэтому материал выполняется только тогда, когда событие находится на родительском div.


Я просто хотел поделиться с тобой кое-чем.
Я получил некоторые трудные времена с ng-mouseenter и ng-mouseleave событий.

примеры:

Я создал плавающее меню навигации, которое переключается, когда курсор находится над значком.
Это меню было вверху каждой страницы.

  • чтобы обработать Показать / Скрыть в меню, я переключаю класс.
    ng-class="{down: vm.isHover}"
  • для переключения vm.isHover, я использую ng событие мыши.
    ng-mouseenter="vm.isHover = true"
    ng-mouseleave="vm.isHover = false"

пока все было хорошо и работало, как ожидалось.
Решение чисто и просто.

входящие проблемы:

в определенном представлении у меня есть список элементов.
Я добавлена панель действий, когда курсор находится над элементом списка.
Я использовал тот же код, что и выше, для обработки поведения.

в проблема:

Я понял, когда мой курсор находится в плавающем меню навигации, а также в верхней части элемента, существует конфликт между собой.
Появилась панель действий, и плавающая навигация была скрыта.

дело в том, что даже если курсор находится над плавающим меню навигации, элемент списка ng-mouseenter запускается.
Для меня это не имеет смысла, потому что я ожидал бы автоматического разрыва распространения мыши события.
Должен сказать, что я был разочарован и потратил некоторое время, чтобы выяснить эту проблему.

первые мысли:

Я попытался использовать эти:

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

Я объединил много событий указателя ng (mousemove, mouveover,... но никто мне не поможет.

решение CSS:

Я нашел решение с простым свойством css, которое я использовать все больше и больше:

pointer-events: none;

в основном, я использую его так (в моих элементах списка):

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

С помощью этого хитрого события ng-mouse больше не будут запускаться, и мое плавающее меню навигации больше не будет закрываться, когда курсор находится над ним и над элементом из списка.

пойти дальше:

как вы можете ожидать, это решение работает, но мне это не нравится.
Мы не контролируем наши события и это плохо.
Кроме того, у вас должен быть доступ к vm.isHover область для достижения этого, и это может быть невозможно или возможно, но грязно так или иначе.
Я могу сделать скрипку, если кто-то захочет посмотреть.

тем не менее, у меня нет другого решения...
Это долгая история, и я не могу дать вам картошку, поэтому, пожалуйста, простите меня, мой друг.
Во всяком случае,pointer-events: none это жизнь, так что запомните это.


если у вас есть доступ к элементу, к которому прикреплено событие внутри mouseout метод, вы можете использовать contains() чтобы увидеть, если event.relatedTarget является дочерним элементом или нет.

As event.relatedTarget - это элемент, в который перешла мышь, если это не дочерний элемент, вы вышли из элемента.

div.onmouseout = function (event) {
    if (!div.contains(event.relatedTarget)) {
        // moused out of div
    }
}

хотя решение вы ссылались на использование jquery, события мыши: mouseenter и mouseleave являются родными событиями dom, поэтому вы можете использовать без jquery.