イベントバブリングを気にせずマウスイベントを使える関数を作ってみた【Javascript】
Javascriptでプラグラムをしていると、誰もが一度は引っかかるで有ろうイベントバブリング。独自でスライドショーなどを作ると、イベントバブリングしても影響が無いようコーディングしたり、コードを修正したりしているはずです!
と言う事で、イベントバブリングを気にせずにマウスクリック/オーバー/アウトを使えるような関数を作ってみました。
マウスクリック/オーバー/アウトをしたのが自分かを調べる関数
メインの関数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function muuClickHover(e, that){ if (!e) e = window.event; if (e.type != 'click' && e.type != 'touchstart' && e.type != 'mouseover' && e.type != 'mouseout') return false; var t = e.target || e.toElement; var f = e.relatedTarget || e.fromElement; switch (e.type){ case 'click' : case 'touchstart' : if (t != that) return false; return true; break; default : for (tmp=f;tmp;tmp=tmp.parentNode){ if (tmp == that) return false; }; return true; break; } } |
この関数にイベントを渡すと、イベントが発生した要素が自分自身なら「true」を返してきます。逆にイベントが発生したのが自分では無かった場合は「false」を返します。
ですので、「true」が返って来た時だけにその後の処理が実行されるようにすることで、イベントバブリングの影響を受けなくします。
【注意※】
この関数は、イベントバブリングを止める関数ではありません。子要素から伝播されてきたイベントを無視する関数ですので、自身が起こしたイベントは親要素に伝達していきます。全てのマウスイベントにコノ関数を挟めば問題無いかと思います。
マウスイベントの書き方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// マウスクリック element.onclick = function (e){ if (muuClickHover(e, this) == false) return false; /* ココに処理を書く */ } // マウスオーバー element.onmouseover = function(e) { if (muuClickHover(e, this) == false) return false; /* ココに処理を書く */ } // マウスアウト element.onmouseout = function(e) { if (muuClickHover(e, this) == false) return false; /* ココに処理を書く */ } |
この関数にイベントと自分自身を引数で渡すように記述します。
サンプルではイベントハンドラで直接書いてますが、イベントリスナーで書いても大丈夫です。下記にイベントリスナーの例も記載して置きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if (document.addEventListener){ element.addEventListener('click', function(e){ if (muuClickHover(e, this) == false) return false; /* ココに処理を書く */ }, false); }else if(document.attachEvent){ // IE用 element.attachEvent('onclick', function(e){ if (muuClickHover(e, this) == false) return false; /* ココに処理を書く */ }); } |
IE用に余分に記述しないといけないのが面倒ですよね。。。
イベントハンドラを1つの要素に複数指定する事が無い場合は、イベントハンドラで直接書いても良いような気がします^^;
関数の簡単な解説
クリックの場合
6 |
var t = e.target || e.toElement; |
6行目でイベントが発生した要素を取得出来ます。そしてその取得要素が、引数で渡されて来た、自分自身と同じかどうかを比較します。
比較した結果、自分自身では無かったら「false」を返します。
マウスオーバー/アウトの場合
7 |
var f = e.relatedTarget || e.fromElement; |
7行目でイベントが発生した要素を取得出来ます。そしてその要素から親要素へと登って行き、自分自身と同じものが出てきたら「false」を返します。
クリックの場合と同じ様に、イベントが発生した要素と自分自身が同じかを比較するだけだと、今回の肝のイベントバブリングに引っかかるのでこの方法となりました。
実際の動いているところのデモ
クリックの動作デモ
クリック回数
0
一番大きい大サイズの要素をクリックすると、「クリック回数」が1つずつ増えていきます。真ん中にある中サイズの・小サイズの要素をクリックしても回数が増えていかない事を確認してくだい。
1 2 3 4 5 6 7 8 9 10 11 |
<div id="clickArea"> <div> <div> </div> </div> </div> <div class="print"> <p>クリック回数</p> <p id="clickCnt">0</p> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var clickCnt = 0; var clickEle = document.getElementById('clickArea'); if (document.addEventListener){ clickEle.addEventListener('click', function(e){ if (muuClickHover(e, this) == false) return false; clickCnt++; document.getElementById('clickCnt').innerHTML = clickCnt; }, false); }else if(document.attachEvent){ // IE用 clickEle.attachEvent('onclick', function(e){ if (muuClickHover(e, this) == false) return false; clickCnt++; document.getElementById('clickCnt').innerHTML = clickCnt; }); } |
オーバー/アウトの動作デモ
オーバー回数
0
アウト回数
0
大サイズの要素に、マウスオーバーすると「オーバー回数」が、マウスアウトすると「アウト回数」が増えていきます。中サイズ・小サイズの要素にマウスオーバー/アウトしても回数が増えていかない事を確認してくだい。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div id="overOutArea"> <div> <div> </div> </div> </div> <div class="print"> <p>オーバー回数</p> <p id="overCnt">0</p> <p>アウト回数</p> <p id="outCnt">0</p> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
var overCnt = 0, outCnt = 0; var overOutEle = document.getElementById('overOutArea'); overOutEle.onmouseover = function(e) { if (muuClickHover(e, this) == false) return false; overCnt++; document.getElementById('overCnt').innerHTML = overCnt; } overOutEle.onmouseout = function(e) { if (muuClickHover(e, this) == false) return false; outCnt++; document.getElementById('outCnt').innerHTML = outCnt; } |
その他のイベントバブル対策 / Javascript
onmouseenter/onmouseleave を使う
オーバー回数
0
アウト回数
0
onmouseover/onmouseoutと似たような動きをしますが、違うのはイベントバブリングをしない事です。子要素からも伝播しないし、親要素へも伝播しません。昔のブラウザでは動かないものもあるらしいですが、最近の主要ブラウザでは動くみたいなので、こちらを使っても良さそうです。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div id="enterSeleaveArea"> <div> <div> </div> </div> </div> <div class="print"> <p>オーバー回数</p> <p id="enterCnt">0</p> <p>アウト回数</p> <p id="seleaveCnt">0</p> </div> |
1 2 3 4 5 6 7 8 9 10 11 |
var enterCnt = 0, seleaveCnt = 0; var enterSeleaveEle = document.getElementById('enterSeleaveArea'); enterSeleaveEle.onmouseenter = function() { enterCnt++; document.getElementById('enterCnt').innerHTML = enterCnt; } enterSeleaveEle.onmouseleave = function() { seleaveCnt++; document.getElementById('seleaveCnt').innerHTML = seleaveCnt; } |
stopPropagation()/preventDefault() を使う
マウス場所
- event.stopPropagation();
-
自身のイベントを親へ伝播させないようにします。
サンプルでは、中サイズ部分にこれを記述してあるので、中サイズ部分にマウスオーバーしても、それが親の大サイズ部分に伝播しないので、【中】とだけ表示されます。
また、子要素からは伝播するので、小サイズ部分にマウスオーバーすると、【小】と言う文字と【中】と表示されていると思います。 - event.preventDefault();
- 今回は確認することができませんが、例えばa要素にコレを指定してあげると、要素をクリックしてもリンクしないようにすることができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<div id="defProeArea"> <div id="defProeInner01"> <div id="defProeInner02"> </div> </div> </div> <div class="print"> <p>マウス場所</p> <p id="defProP"> <span id="defProP01"></span> <span id="defProP02"></span> <span id="defProP03"></span> </p> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
var area = document.getElementById('defProeArea'); var inner01 = document.getElementById('defProeInner01'); var inner02 = document.getElementById('defProeInner02'); var defProP01 = document.getElementById('defProP01'); var defProP02 = document.getElementById('defProP02'); var defProP03 = document.getElementById('defProP03'); area.onmouseover = function (){ defProP01.innerHTML = '【大】'; } area.onmouseout = function (){ defProP01.innerHTML = ''; } inner01.onmouseover = function (e){ e.preventDefault(); e.stopPropagation(); defProP02.innerHTML = '【中】'; } inner01.onmouseout = function (){ defProP02.innerHTML = ''; } inner02.onmouseover = function (){ defProP03.innerHTML = '【小】'; } inner02.onmouseout = function (){ defProP03.innerHTML = ''; } |
その他のイベントバブル対策 / jQuery
jQuery固有の方法もあります。
hover(over, out) を使う
1 2 3 4 5 6 7 8 9 10 11 12 |
$('要素').hover( function () { /* ココにオーバー時の処理を書く */ }, function () { /* ココにアウト時の処理を書く */ } ); |
基本的な動きは「onmouseenter/onmouseleave」を使っているのでサンプルは特に載せません。
return false を使う
1 2 3 4 5 6 |
$("要素").click(function () { /* ココにアウト時の処理を書く */ return false; }); |
「preventDefault()/stopPropagation()」の2つを合わせたような動きをします。同じくサンプルは特にのせません。
jQueryを使わずJavascriptだけで動かす場合は、「return false」を記述してもそのまま親要素へ伝播していきます。
チラシの裏
今回の関数は、「イージングの動き見本(サンプル)【Javascript / jQuery】」を作る中で、赤い球をクリックした時の不具合を解消する為に作りました。。。が、私が知らないだけで、もっと簡単な関数とか有ったら教えてください^^;
・ケゥ
・ムゥ
・ウ・ヤゥ`・ヨ・鬣ノ t・キ・罕ト。セ2019ミツラソアャーイヘィリ?
2019ウャネヒ壥。セシエネユーkヒヘ。ソ
ヤレ珠メサ鶴リ怏モヨミミナモテ、「、?
。セ」イ」ー」ア5ネヒ壥圓オス。ソシ、ーイヘィリ?
エヒ壥アセ…