お寿司か焼き肉食べたい

まじめな事からしょーもない事まで
めにゅーを開く(投げやり)

そんなんアレされたら。アレよ

というわけで、イベントハンドラのお話。
色々ありますが、適材適所で使い分けをします。

onblur

主にフォーム要素に対して使用します。
指定されたフォーム要素からフォーカスが外れた時に処理が走ります。

window.onload = function()
{
 var elem01 = document.getElementById('elem01');
 elem01.onblur = function()
 {
  alert('フォーカスが外れました。');
 }
}

onfocus

主にフォーム要素に対して使用します。
指定されたフォーム要素にフォーカスが当たった時に処理が走ります。

window.onload = function()
{
 var elem02 = document.getElementById('elem02');
 elem02.onfocus = function()
 {
  alert('フォーカスが当たった。');
 }
}

onchange

主にフォーム要素に対して使用します。
指定されたフォーム要素の内容が変更された時点で処理が発生します。

window.onload = function()
{
 var elem03 = document.getElementById('elem03');
 elem03.onchange = function()
 {
  alert('内容が変わった。');
 }
}

onselect

主にフォーム要素に対して使用します。
指定されたフォーム要素の内容が変更された時点で処理が発生します。

window.onload = function()
{
 var elem04 = document.getElementById('elem04');
 elem04.onselect = function()
 {
  alert('内容が変わった。');
 }
}

onsubmit

主にフォーム要素に対して使用します。
サブミットされるときに処理を実行します。

window.onload = function()
{
 var elem05 = document.getElementById('elem05');
 elem05.onsubmit = function()
 {
  if(window.confirm("送信しようとしますが、よろしいですか?"))
  {
   alert('送信開始');
  }
  else
  {
   alert('何もしない');
   return false;
  }
 }
}

onload

画像まで読み込まれた時に実行させます。
基本的にwindowオブジェクトに対して使用します。

window.onload = function()
{
 // 全て読み込まれたら処理が開始される
}

onclick

要素をクリックした時に処理が実行されます。

クリック
window.onload = function()
{
 var elem06 = document.getElementById('elem06');
 elem06.onclick = function()
 {
  alert('クリックされました。');
 }
}

ondblclick

要素をダブルクリックした時に処理が実行されます。

ダブルクリック
window.onload = function()
{
 var elem07 = document.getElementById('elem07');
 elem07.ondblclick = function()
 {
  alert('ダブルクリックされました。');
 }
}

onKeyUp

フォーム要素で使用します。
押していたキーを上げた時に処理が実行されます。

window.onload = function()
{
 var elem08 = document.getElementById('elem08');
 elem08.onkeyup = function()
 {
  alert('キーが上がりました。');
 }
}

onkeydown

フォーム要素で使用します。
キーを押した時に処理が走ります。

window.onload = function()
{
 var elem09 = document.getElementById('elem09');
 elem09.onkeydown = function()
 {
  alert('何か押されました。');
 }
}

onkeypress

フォーム要素で使用します。
キーを押している間処理を行います。

window.onload = function()
{
 var elem10 = document.getElementById('elem10');
 elem10.onkeydown = function()
 {
  alert('何か押されました。onkeypress');
 }
}

onkeypressとonkeydown

ただ単純に、何かキーが入力されたら、的な話ならどっちを使っても
問題はないです。
ただ、それが何のキーなのか?を見る時は(ブラウザによって動作がかわるようですが)
使い分ける必要があるっぽいですね。
今回はそこまでやりません。

onmouseover

要素にマウスが乗った時に動作します。

window.onload = function()
{
 var elem11 = document.getElementById('elem11');
 elem11.onmouseover = function()
 {
  alert('マウスがのった');
 }
}

onmouseout

要素にマウスが外れた時に動作します。

window.onload = function()
{
 var elem12 = document.getElementById('elem12');
 elem12.onmouseout = function()
 {
  alert('マウスがどこかいった!');
 }
}

onmousedown

要素上で、マウスクリック(右左ホイールクリックも含む)された時に動作します。

window.onload = function()
{
 var elem13 = document.getElementById('elem13');
 elem13.onmousedown = function()
 {
  alert('押された');
 }
}

onmouseup

要素上で、マウスクリックを上げた時に動作します。

window.onload = function()
{
 var elem14 = document.getElementById('elem14');
 elem14.onmouseup = function()
 {
  alert('クリックおわり');
 }
}

onmousemove

要素上マウスが動いた時に動作します。
少しでも動いた瞬間に動作するので、動作頻度が非常に高いです。

動かしたら+1していくわ!!!
window.onload = function()
{
 var elem15 = document.getElementById('elem15');
 var elem15Int = 0;
 elem15.onmousemove = function()
 {
  elem15Int++;
  elem15.childNodes[1].value = elem15Int;
 }
}

JSのイベントってどう動いてるかのお話。

ここまでで一通りイベントを紹介してきました。
なお、いらねぇだろってのは省いていますので、イベントハンドラ一覧は後で目を通しておくと
良い感じだと思います。

さて、イベントの種類についてはこんなもんとして、ではそのイベントはどうやって動いているのか?
きちんとした動作ルールがあるので、それらを頭に叩き込んでおきましょう。

キャプチャリングフェーズとバブリングフェーズ

はい、JSイベントと言えばこの2つの言葉が飛び交います。
HTMLはDOM構造なのです。で、指定した所をいきなりビューンと見に行って動かすわけでなく
上から順番にちまちま確認して降りて行って、処理を実行するなど、DOM構造にそって動いていくわけです。
これを [イベントの伝播] と呼びます

キャプチャリングフェーズ

まずはキャプチャリングフェーズから
そうね。キャプチャリングフェーズってのは、上述した[上から順番にちまちま確認して降りてくる]の状態を指します。
例えば

<html>
  <body>
    <div>
     <p>
      <a href="javascript:void(0)" id="clickHref"></a>
     </p>
    </div>
  </body>
</html>

こんな構造があって、#clickHrefに対してクリックイベントをつけたとする。
すると、ブラウザはまず、上から順番に
Window→document→html→body→div→p→a#clickHref
ってな順番でちまちま降りてくるわけです。
これを [キャプチャリングフェーズ]と呼びます。
イベント発火時は常に最頂点から順番にくる 覚えておきましょう。

上から順番にかー。なるほどねぇー

上から攻めてくるぞ!気をつけろ!!!
なんですが、慌てずに続きを

<div id="test1" class="mb20" style="width:300px;background-color:#EEF1F2;">
  <div id="test2" style="width:250px;background-color:#3BC8A2;">
    <div id="test3" style="width:200px;background-color:#5398C1;">
      <a href="javascript:void(0);" id="test4">
        クリックしたまえ
      </a>
    </div>
  </div>
</div>

<script>
  var elemTest1 = document.getElementById('test1'),
      elemTest2 = document.getElementById('test2'),
      elemTest3 = document.getElementById('test3'),
      elemTest4 = document.getElementById('test4');

  elemTest1.addEventListener('click',function(e)
  {
    alert('elemTest1');
  },false);
  elemTest2.addEventListener('click',function(e)
  {
    alert('elemTest2');
  },false);
  elemTest3.addEventListener('click',function(e)
  {
    alert('elemTest3');
  },false);
  elemTest4.addEventListener('click',function(e)
  {
    alert('elemTest4');
  },false);
</script>

上からくるって事はさ、test1→test2→test3→test4の順番でアラートが出るのね。
へー(๑´ڡ`๑)
↓リンク部分をクリックしよう

嘘ンゴ。本当はtest4→test3→test2→test1の順番だンゴ

なんでや!!!話が違うやないか!!!

いや、誰もキャプチャリングフェーズで実行させるとか言うてませんし。へへへ。
キャプチャリングフェーズとバブリングフェーズ、JSのデフォルトでは、バブリングフェーズで処理が実行されます。
つまり、キャプチャリングフェーズってのは、通常
指定要素最後(孫全て)まで見に行って、それまでに巡ってきたDOM要素にユーザーイベント(クリック等)が無いかどうか、クリックされた要素かどうか、を確認するフェーズ
と言えます。(クソ長い)
キャプチャー、意味的には捕獲ってあります。つまり、何かしら行動を起こした所に対応イベントあったら実行用にどう処理するかメモして覚えとくね!ってニュアンスでOKです。

もう少しだけ細く

なるほど、上から順番に確認しながら降りてくる
さてさて、このデモ面白い構造してるからもう少しだけ動作の確認をしましょう。
このデモ、各divに対してwidthとbackground-colorをつけています。
親要素から順番に小さくなる感じですね。
順番にクリックしてもらっていけば分かると思いますが、キャプチャリングフェーズでは、クリックされた要素で止まっているのがわかります。
例えば、#test3の要素をクリックした場合
window

(略)

div#test1 お、ここクリックされとるしイベント付与されてるやん。メモしとこ

div#test2 お、ここクリックされとるしイベント付与されてるやん。メモしとこ

div#test3 お、ここクリックされとるしイベント付与されてるやん。メモしとこ

a#test4 ここクリックされとらんわ。

キャプチャリングおわり

みたいな流れですね。クリックされてねぇんだからそら動かんやろって当たり前のお話ですが
一応。ちょっとくどいかしらね。

バブリングフェーズ

キャプチャリングフェーズで最後まで確認してくれました。
いよいよここから実行していきます。
で、さっきのデモで分かるように、最下層から順番に実行されていき、キャプチャリングフェーズとは逆に上へ上へ上がっていく感じになります。
DOM構造は順番に見ないといけない これですね。
ちなみに、泡のように浮かんでくる様からバブリングって名付けたとかなんとか。

バブリングでの制御

そんな感じでJSはイベントの伝播を行いながら動いているのがわかりました。
つまり、がぶった要素に同じイベントがあれば実行されちゃうのですね。
同じようなデモですが、もっと視覚的にわかりやすいようにマウスオーバーのイベントでデモやり直してみました。

親要素
子要素
マウスオーバーで色がかわるよ!

おかわりいただけるだろうか
まぁ、上のデモでもそうでしたし、正常にキャプチャリングとバブリングが動いている証拠ですよね。
ただ、これじゃ子要素だけ動かないじゃないか!!!みたいな時の対処方法をば

親へ伝播させたくないんですけど。

まずは親の伝播を防ぐ方法ですが。
stopPropagationを使いましょう。

親へのイベントの伝播を止めるぞー!
window.onload = function()
{
 // 親要素イベント
 var elem18 = document.getElementById('elem18');
 elem18.onmouseover = function()
 {
   elem18.style.backgroundColor = "#BBCCDD";
 }
 elem18.onmouseout = function()
 {
   elem18.style.backgroundColor = "#ddd";
 }

 // 子要素イベント
 var elem19 = document.getElementById('elem19');
 elem19.onmouseover = function(e)
 {
  e.stopPropagation();
  elem19.style.backgroundColor = "#BBCCDD";
 }
 elem19.onmouseout = function(e)
 {
  e.stopPropagation();
  elem19.style.backgroundColor = "#B4CFFB";
 }
}

というわけで解説。
まず、イベント処理のfunctionの引数にご注目
function(e)
eってなんだよ。って思われるハズですが。ここの引数を指定することにより
イベントオブジェクトを取得することができます。
名前はなんでもよいです。
stopPropagationってのはイベントオブジェクトのメソッドです。
どのイベントを?って意味になるのでこの指定をします。
なので、【e.stopPropagation();】とします。

で、e.stopPropagation();が実行されることにより
これ以上の親要素イベントは無視する
と制御することができます。わーい
時系列で書くと
window

(略)

div#elem18 お、ここマウスオーバーされとるしイベント付与されてるやん。メモしとこ

div#elem19 お、ここマウスオーバーされとるしイベント付与されてるやん。メモしとこ。え?親行ったらアカンのです。おっけー

バブリングするぞー

div#elem19 よっしゃ背景色変えたろ。

おわり

もうちょっと

まぁこれで親への伝播はなくなったわけで、ハッハーって感じなのですが。
例えばaタグ こいつってデフォルトで画面遷移する能力をもってるわけですね
あれ?じゃぁaタグにイベント付与できないやんけ!
はい。そんな時はこれ
e.preventDefault();

window.onload = function()
{
 var elem20 = document.getElementById('elem20');
 elem20.onclick = function(e)
 {
   alert('親要素のクリックイベントだよー。これがでたら遷移止めれてるのね!');
 }
 var elem21 = document.getElementById('elem21');
 elem21.onclick = function(e)
 {
   alert('aタグクリックしたやで');
   e.preventDefault();
 }
}

楽勝ですよね。他にも、チェックボックスやら云々の動作もキャンセルしちゃうこともできるようです。 ちなみに、親クリックイベントも走ってますが、これ邪魔くさいなぁって思う時は
e.preventDefault();
e.stopPropagation();
両方指定してやりましょう。
あ。return false;でもいいですよ。

window.onload = function()
{
  var elem22 = document.getElementById('elem22');
  elem22.onclick = function(e)
  {
    alert('aタグクリックではでないヤツ');
  }
  var elem23 = document.getElementById('elem23');
  elem23.onclick = function(e)
  {
    alert('aタグクリックしたやで');
    e.preventDefault();
    e.stopPropagation();
  }
}

イベント追加方法

イベントの追加方法です。さっきしただろ!いい加減にしろ!
ずらずらとやった方法だけがイベントの追加方法ではないです。
別手法で追加させることができます。

addEventListener('イベント名',処理,捕捉フェーズ)

第一引数・第二引数は見たまんまのお話。
補足フェーズってなんだよ。

捕捉フェーズ

ここに指定できるのは、【true】【false】のどちらか。
で、ここでバブリングの話。
子要素から始まって、順番に親要素へイベントが浮いていく話をしました。
で、ここで、【true】を指定することで、この親要素が先に動作することができます。
ちなみに【false】とすると、通常バブリングの通りの動きになります。つまりデフォルト

window.onload = function()
{
 var elem24 = document.getElementById('elem24');
 elem24.addEventListener('click',function(e)
 {
  alert('親要素');
 },true);
 var elem25 = document.getElementById('elem25');
 elem25.addEventListener('click',function(e)
 {
  alert('子要素');
 },false);
}
window.onload = function()
{
 var elem26 = document.getElementById('elem26');
 elem26.addEventListener('click',function(e)
 {
  alert('親要素');
 },false);
 var elem27 = document.getElementById('elem27');
 elem27.addEventListener('click',function(e)
 {
  alert('子要素');
 },false);
}

話を元に戻す

引数のお話をしました。
そいで、使い方は例の通り。
で、onclickとかと違って、こいつは【イベントが複数登録できる】のです。
on~系は処理が上書きされます。
on系とaddEventListenerは別物です。組み合わせても大丈夫です。(両方のイベントが生きる)

最後に短くまとめ

結構ダラダラといっぱい書いちゃいましたね。
最後に短くまとめて終わりにします。

  • windowから順番に最子要素に向かって下へ下へイベント確認 キャプチャリング
  • 最子要素から順番に親に向かって処理実行 バブリング!
  • そのイベントより親の処理実行したくない! stopPropagation()
  • aタグとかの遷移したくない!別のことさせて! preventDefault()
  • 遷移したくないし、親も動かないで stopPropagation()とpreventDefault()かreturn false;