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



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



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



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



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



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

604   17  

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, проверьте это...

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

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

EDIT пример вложенных дети

EDIT исправлено, надеюсь, кросс-браузер

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,EDIT обновили ссылку

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

примеры:

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

  • чтобы обработать show / hide в меню, я переключаю класс.
    ng-class="{down: vm.isHover}"
  • для переключения vm.ишовер, я использую НГ событие мыши.
    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 является дочерним элементом или нет.

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

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

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

Comments

    Ничего не найдено.