web-dev-qa-db-ja.com

jQueryを使用せずに、親の絶対divの子要素をホバーするときのマウスアウトを防ぐ

絶対位置のdivでonmouseout関数に問題があります。マウスがdiv内の子要素にヒットすると、mouseoutイベントが発生しますが、マウスが親の絶対divから外れるまで発生しません。

Jqueryなしで子要素にヒットしたときにmouseoutイベントが発生しないようにするにはどうすればよいですか。

これはイベントのバブリングと関係があることは知っていますが、これを解決する方法を見つけることができません。

私はここで同様の投稿を見つけました: 子要素によってトリガーされたマウスアウトイベントを無効にする方法?

ただし、そのソリューションはjQueryを使用します。

145
John
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/

NOTEこれは直接の親のみをチェックします。親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;
}

そして、新しい JSFiddleEDITリンクを更新しました

87
Amjad Masad

onmouseleaveを使用します。

または、jQueryでmouseleave()を使用します

それはあなたが探している正確なものです。例:

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

または、jQueryで:

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

例は here です。

95
PHPWannaBePro

場合によっては動作する単純な純粋なCSSソリューションIE11以降 )では、子供の pointer-eventsnoneに設定することにより

.parent * {
     pointer-events: none;
}
84
Zach Saucier

以下は、以下に基づいたよりエレガントなソリューションです。これは、複数のレベルの子供から発生するイベントを説明します。また、クロスブラウザの問題も考慮します。

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);
27
Sam-Elie

私にインスピレーションを与えた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
    }
12
Lawrence Mok

JQueryを使用している場合は、「mouseleave」関数も使用できます。これは、これらすべてを処理します。

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

do_somethingは、マウスがtargetdivまたはその子のいずれかに入ったときに起動します。do_something_elseは、マウスがtargetdivおよびその子のいずれかを離れたときにのみ起動します。

12
Jamie Brown

mouseleave()を試してください

例:

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

   </div>
</div>

;)

7
Jean-Philippe

Quirksmode に必要な答えはすべてあると思います(異なるブラウザーのバブリング動作とmouseenter/mouseleaveイベント)、しかしそれに対する最も一般的な結論はイベントバブリングの混乱isJQueryやMootools(mouseenterおよびmouseleaveイベント。これはまさにあなたが直観したものです。

彼らがそれをどのように行うかを見てください、あなたが望むなら、自分でそれをしてください
orすることができます カスタムを作成する イベント部分(およびその依存関係)だけでMootoolsの「リーン平均」バージョン。

6
Ruben

私は非常に簡単な解決策を見つけました、

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>

それが役に立てば幸い :)

5
Arminius

onmouseoutの代わりにonmouseleaveを使用します。

あなたは私たちにあなたの特定のコードを見せていないので、あなたの特定の例でそれを行う方法を示すことはできません。

しかし、それは非常に簡単です。onmouseoutをonmouseleaveに置き換えるだけです。

それだけです:)それで、簡単です:)

方法がわからない場合は、次の説明を参照してください。

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

ケーキの平和:)それをお楽しみください:)

4
kavi

これを処理するには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>
1
selbie

mouseoutメソッド内でイベントが関連付けられている要素にアクセスできる場合、contains()を使用して、event.relatedTargetが子要素であるかどうかを確認できます。

event.relatedTargetはマウスが渡された要素であるため、子要素でない場合は、要素からマウスアウトしました。

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

Angular 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
Alan Torrico

私はこれで魅力のように動作させます:

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>

より一般的なのは、1つのdivだけではなく、各レイヤーにid="..."を追加する必要がないことです。

1
z666zz666z

参照した solution はjqueryを使用していますが、 mouseenter および mouseleave はネイティブdomイベントであるため、jqueryなしで使用できます。

1
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
Michael Vaganov

元の要素のオフセットをチェックして要素の境界のページ座標を取得し、マウスアウトがこれらの境界から外れたときにのみマウスアウトアクションがトリガーされるようにします。汚れていますが、動作します。

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

私はあなたと何かを共有したかっただけです。
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は命ですから、覚えておいてください。

0
C0ZEN

親要素に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