jQuery없이 부모 절대 div의 자식 요소를 가리킬 때 onmouseout 방지


169

onmouseout절대 포지티브 div에서 함수에 문제가 있습니다. 마우스가 div의 자식 요소에 부딪 치면 mouseout 이벤트가 발생하지만 마우스가 부모 인 절대 div에서 벗어날 때까지 마우스를 발사하지는 않습니다.

mouseoutjquery없이 자식 요소에 도달했을 때 이벤트가 발생 하지 않도록하려면 어떻게해야합니까 ?

나는 이것이 이벤트 버블 링과 관련이 있다는 것을 알고 있지만, 이것을 해결하는 방법을 찾는 데 운이 없다.

비슷한 게시물을 발견했습니다 : 자식 요소에 의해 트리거 된 mouseout 이벤트를 비활성화하는 방법은 무엇입니까?

그러나 그 솔루션은 jQuery를 사용합니다.


나는 타임 아웃을 사용하여 문제를 해결하고 자식 요소의 호버에 그것을 삭제 결국
요한

안녕하세요, 귀하의 데모를 보았지만 오른쪽 하단 패널의 요소를 살펴보면 아무런 반응이 없습니까?
John

1
자식 요소를 마우스 오버하면 javascript mouseover / mouseout 부모 이벤트에서 마우스 아웃을 방지하려는 경우이 답변을 찾았습니다 .
user823527

답변:


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

CSS와 HTML이 필요한 빠른 JsFiddle 데모를 만들었습니다.

크로스 브라우저 지원을위한 수정 된 링크 수정 http://jsfiddle.net/RH3tA/9/

부모 div에 자식이 중첩되어 있으면 바로 부모 만 확인한다는 점에 유의 하십시오. "일반 요소"를 찾고있는 부모 요소를 통과해야합니다.

중첩 된 자식에 대한 편집

편집 크로스 브라우저를 위해 수정되었습니다.

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 업데이트 링크


1
테스트 할 수 있도록 바이올린에 mouseout 이벤트를 추가해야합니다. 경고 나해야 할 일.
John

죄송하지만 alert ( 'MouseOut')가있는 것 같지만 작동하지 않습니다? JS 라이브러리 옵션없이 실행했습니다
John

사파리와 크롬에서 테스트되었지만 모든 것이 작동해야합니다! 브라우저가 무엇입니까?
Amjad Masad 2016 년

2
손자 자녀가 있다면 어떻습니까? 아니면 위대한 손자? 즉, 당신은 그냥 이민 어린이 대신 재귀 솔루션을 가질 수 있습니까?
Roozbeh15

19
작동하지 않습니다. mouseleave정답입니다
Code Whisperer

126

사용하십시오 onmouseleave.

또는 jQuery에서 mouseleave()

당신이 찾고있는 정확한 것입니다. 예:

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

또는 jQuery에서 :

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

예가 여기 있습니다 .


3
onMouseLeave거품이 생기지 않아서 너무 사용했습니다.
Alecz

많은 시간을 절약했습니다. thnx
npo

mouseleave취소 할 수 없습니다.
grecdev

@grecdev, 더 말해!
벤 휠러

96

경우에 따라 작동 하는 더 간단한 순수 CSS 솔루션 ( IE11 이상 )의 경우 어린이 pointer-events를 다음과 같이 설정하여 제거 할 수 있습니다.none

.parent * {
     pointer-events: none;
}

4
훌륭한! 방금 내 문제를 해결했습니다!
Anna_MediaGirl

4
이것은 첫 번째 또는 적어도 두 번째 대답이어야합니다. 번거로운 이벤트 리스너와 함께 갈 준비가되어있어서 내 문제도 완전히 해결했습니다. 너무 간단합니다!
Mickael V.

9
이렇게하면 마우스 아웃이 발생하지 않지만 메뉴의 포인트 인 실제 자식이 선택 항목으로 클릭되는 것을 방지합니다.
johnbakers

@hellofunk 그렇기 때문에 클릭 이벤트를 부모에게 적용해야합니다. 필요한 정확한 코드는 구현에 따라 다릅니다.이 답변은 단지 pointer-events속성 사용을 제안 합니다
Zach Saucier

1
이 솔루션은 그것들을 차단하기 때문에 영역 안에 다른 컨트롤러 요소 (편집, 삭제)가없는 경우에만 작동합니다.
Zoltán Süle

28

아래에 나온 것을 기반으로 한보 다 우아한 솔루션이 있습니다. 그것은 여러 레벨의 어린이들로부터 발생하는 사건을 설명합니다. 또한 브라우저 간 문제도 설명합니다.

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

Sam Elie, 이것은 IE, Safari 또는 Opera에서 작동하지 않는 것 같습니다. 이 스크립트의 크로스 브라우저 버전이 있습니까? Firefox와 Chrome에서 매력처럼 작동합니다. 감사.

1
위 함수를 스크립트에 붙여 넣으면 Dreamweaver와 FF에서 첫 번째 줄 "function onMouseOut (this, event) {"에 오류가 발생합니다. "this"를 매개 변수로 넣을 수없는 것 같습니다. 입력 매개 변수에서 "this"를 제외하면 일종의 효과가 있다고 생각하지만 "알지 못하는 것"을 알고 있기 때문에 확실하지 않습니다.
TARKUS

1
this함수 정의 줄 @GregoryLewis를 제외하고는 같은 줄의 Chrome에서 같은 문제가 발생했습니다. 또한 크로스 브라우저를 더 지원하려면 다음을 시도하십시오. if (window.addEventListener) {document.getElementById ( 'parent'). addEventListener ( 'mouseout', onMouseOut, true); } else if (window.attachEvent) {document.getElementById ( 'parent'). attachEvent ( "onmouseout", onMouseOut); }
DWils

아주 잘 생겼어요! 이전 브라우저에 대한 지원이 필요한 경우 최상의 답변입니다.
BurninLeo

13

저에게 영감을 준 Amjad Masad에게 감사드립니다.

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
    }

13

onmouseout 대신 onmouseleave를 사용하십시오.

특정 코드를 보여주지 않았으므로 특정 예제에서 코드를 표시하는 방법을 보여줄 수 없습니다.

그러나 매우 간단합니다. onmouseout을 onmouseleave로 바꾸십시오.

그게 다야 :) 그래서 간단합니다 :)

방법이 확실하지 않은 경우 다음에 대한 설명을 참조하십시오.

https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onmousemove_leave_out

케이크의 평화 :) 그것을 즐기십시오 :)


비슷한 소리가 나면 확인해 볼 가치가 있습니다.
Chris

12

jQuery를 사용하는 경우 "mouseleave"기능을 사용할 수도 있습니다.이 기능은이 모든 것을 처리합니다.

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

do_something은 마우스가 targetdiv 나 그 자식 중 하나에 들어갈 때 발생하고 do_something_else는 마우스가 targetdiv와 그 자식 중 하나를 떠날 때만 발생합니다.


8

생각 쿼크 모드는 모든 당신이 필요로하는 답변 (다른 브라우저 버블 링 행동하고있다 mouseenter /하는 MouseLeave 이벤트),하지만 난 그 이벤트 버블 링 혼란에 가장 일반적인 결론은 생각 입니다 JQuery와 또는 Mootools의합니다 (이 같은 프레임 워크의 사용 mouseenter을 하고 mouseleave 이벤트, 이것은 당신이 직감 했던 것입니다).

원하는 경우 직접 수행
하거나 이벤트 부분 (및 그 종속 항목)만으로 Mootools 의 사용자 정의 "최소 평균"버전을 만들 수 있는 방법을 살펴보십시오 .


7

시험 mouseleave()

예 :

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

   </div>
</div>

;)


5

매우 간단한 해결책을 찾았습니다.

onmousout = "myfunc ()"이벤트보다 onmouseleave = "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>

그것이 도움이되기를 바랍니다 :)



2

이것을 처리하는 두 가지 방법이 있습니다.

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>

onmouseover 대신 onmouseout에서이 작업을 수행하려면 어떻게해야합니까?
John

죄송합니다. 내 잘못이야. 위 코드에서 모든 "마우스 오버"참조를 "마우스 아웃"으로 변경했습니다. 그렇게해야합니다.
selbie

첫 번째 방법의 경우, event.target은 마우스가 자식 요소를 넘어갈 때 항상 부모 요소와 일치하므로 작동하지 않습니다.
John

두 번째 방법에서도 마찬가지입니다. 마우스가 자식 요소를 입력하면 여전히 이벤트를 트리거합니다
John

1

나는 이것을 매력처럼 작동시킵니다 :

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

그런 다음 DIV 태그는 다음과 같습니다.

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

따라서 더 일반적인 것은 하나의 div뿐만 아니라 id="..."각 레이어 에 추가 할 필요가 없습니다 .


1

mouseout메소드 내부에서 이벤트가 첨부 된 요소에 액세스 할 수있는 경우 contains()이를 사용 하여 event.relatedTarget하위 요소인지 여부를 확인할 수 있습니다 .

으로 event.relatedTarget는 자식 요소가 아닌 경우 마우스로 통과되는 요소, 당신은 요소 밖으로 마우스를 올리면있다.

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

1

각도 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');
 }
}

0

원래 요소의 오프셋을 확인하여 요소 경계의 페이지 좌표를 얻은 다음 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
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
});

답변자에게 설명을 부탁드립니다.
Sebass van Boxel

0

부모 요소에 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에있을 때만 물건이 실행됩니다.


0

난 그냥 당신과 뭔가를 공유하고 싶었다.
나는 몇 가지 어려움을 가지고 ng-mouseenterng-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인생 이니 기억하세요

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.