Запретить onmouseout при наведении на дочерний элемент родительского абсолютного div БЕЗ jQuery - PullRequest
143 голосов
/ 15 января 2011

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

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

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

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

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

Ответы [ 19 ]

1 голос
/ 12 декабря 2018

На угловых 5, 6 и 7

<div (mouseout)="onMouseOut($event)"
     (mouseenter)="onMouseEnter($event)"></div>

Затем на

import {Component,Renderer2} from '@angular/core';
...
@Component({
 selector: 'app-test',
 templateUrl: './test.component.html',
 styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit, OnDestroy {
...
 public targetElement: HTMLElement;

 constructor(private _renderer: Renderer2) {
 }

 ngOnInit(): void {
 }

 ngOnDestroy(): void {
  //Maybe reset the targetElement
 }

 public onMouseEnter(event): void {
  this.targetElement = event.target || event.srcElement;
  console.log('Mouse Enter', this.targetElement);
 }

 public onMouseOut(event): void {
  const elementRelated = event.toElement || event.relatedTarget;
  if (this.targetElement.contains(elementRelated)) {
    return;
  }
  console.log('Mouse Out');
 }
}
1 голос
/ 27 января 2018

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

1 голос
/ 14 мая 2017

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

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

div.onmouseout = function (event) {
    if (!div.contains(event.relatedTarget)) {
        // moused out of div
    }
}
1 голос
/ 28 марта 2012

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

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="..." на каждый слой.

1 голос
/ 15 января 2011

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

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

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>
0 голосов
/ 02 мая 2017

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

Решение CSS:

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

pointer-events: none;

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

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

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

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

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

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

0 голосов
/ 25 января 2012

Я проверяю смещение исходного элемента, чтобы получить координаты страницы границ элемента, затем проверяю, что действие 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
}
}
0 голосов
/ 02 октября 2012
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 голосов
/ 13 сентября 2013

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

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

...