JS イベントまとめ

##参照
パーフェクトJavaScript

##イベントドリブンプログラミング
- あるイベントに対して、どのような処理をするのかを登録する
- ブラウザがイベントを起こすたびにその登録した処理が実行される
- 登録する処理のことを「イベントハンドラ」「イベントリスナ」と呼ぶ

##イベント例
- ある要素をクリックする
- ある要素の上にマウスを動かす
- キーボードで特定のキーを押す
- ページが読み込まれたり、別のページに遷移する時に起こるイベント

##DOM Level2
- モダンブラウザは、DOM Level2に準拠
- IE8は'独自のイベントモデル'を実装している。APIとして別物なので注意が必要


##古い書き方　「イベントハンドラ」

- 1つの要素/イベントについて1つしか設定できない

####「古い書き方1」HTML要素の属性に指定する　(直書き)

```js
<input id="foo" type="button" value="foo" onclick="alert('bar');alert('baz')">
```

- コードが複数行になる場合はセミコロンで区切る
- HTMLは大文字と小文字区別しない

####「古い書き方2」DOM要素のプロパティに指定する

```js

//イベントハンドラに設定するものは関数そのものにすること。()はつけない。

var btn = document.getElementById('foo');
function sayFoo(){
　alert('foo');
}

btn.onclick = sayFoo;

```

```間違い例.js

//関数を実行した返り値を設定することになるので誤り
btn.onclick = sayFoo();
```

#【イベントリスナ】

- 複数のイベントを設定できる
- EventTarget.addEventListener()を利用する

```基本形.js

var btn = document.getElementById('foo');
btn.addEventListener('click', function(e){
　alert('foo');
}, false);
```
(※IE8以前では使用できない / ※IEではattachEvent()メソッドを利用)


##「キャプチャリングフェーズ」と「パブリングフェーズ」を第3引数で指定。

- DOM Level2では、この引数は必須パラメータ。
- DOM Level3では、この引数を省略した場合には、パブリングフェーズで実行される。
- イベントハンドラは、パブリングフェーズで実行される。
- キャプチャリングフェーズで実行する処理を設定したい場合はEventTarget.addEventListenner()メソッドを利用する。

- IEでは、イベントリスナは常にパブリングフェーズで実行される。

```同一イベントリスナの登録.js

var btn = document.getElementById('foo');
function sayHello(){
　alert('Hello');
}

btn.addEventListener('click',sayHello, false);
btn.addEventListener('click',sayHello, false); //同じイベントリスナは無視
btn.addEventListener('click',sayHello, true);//フェーズが異なれば別のものとして登録される
```

###addEventListener()の実行順序

```イベントリスナの実行順序.js

var btn = document.getElementById('foo');
function sayFoo(){
　alert('foo');
}

function sayBar(){
　alert('bar');
}

function sayBaz(){
　alert('baz');
}

btn.addEventListener('click',sayFoo,false);
btn.addEventListener('click',sayBar,false);
btn.addEventListener('click',sayBaz,false);
btn.addEventListener('click',sayFoo,false); //これは無視される
```

- Firefox,Chrome,Safariは、foo,bar,bazの順に表示される。
- Operaの場合は、bar,baz,fooとなる。

#イベントリスナオブジェクト

イベントリスナとしては単なる関数を指定するのが普通だが、ブラウザによってはhandleEvent()メソッドを実装した「オブジェクト」を指定することもできる。

```js

var btn = document.getElementById('foo');
var eventListener = {
message:'This is an event listener object.',
handleEvent:function(e){
　alert(this.message);
}
};

btn.addEventListener('click',eventListener,false);

//ボタンクリック時に'This is an event listener object.'というメッセージダイアログが表示
```

####イベントターゲット

- イベントが発火した要素。(イベントオブジェクトのtargetプロパティで参照)

####リスナーターゲット

- イベントリスナが登録されている要素。(イベントオブジェクトのcurrentTargetプロパティで参照)


#イベントハンドラ/イベントリスナ内でのthis

イベントハンドラ内でのthisが参照するオブジェクトは、イベントハンドラを設定した要素自身になる。

```js
document.getElementById('foo').onclick = function(/*thisは#fooの要素*/);
```

```js
var Listener = function(){};
lib.handleClick = function(event)
document.getElementById('foo').onclick = lib.handleClick;

//lib.handleClick内でのthisはlibではなく#fooの要素
```

```js
document.getElementById('foo').onclick = function(event){
　lib.handleClick(event);
};
//lib.handleClick内でのthisはlibになる
```

#イベント発火

イベントは主にユーザーの操作が引き金となって発生する。

例)ユーザーがWebページを閲覧している際にもっとも多く発生するイベントはmousemoveイベント。マウスポインタが動いている間中発生し続ける。

#イベントの伝播

```sample.html

<html>
 <body>
  <div id="foo">
　　<button id="bar">sample</button>
　</div>
 </body>
</html>
```

![スクリーンショット 2016-03-07 18.46.07.png](https://qiita-image-store.s3.amazonaws.com/0/62264/5b09df71-7840-4e13-95ad-22757a253fd9.png)

- ターゲットフェーズ

オブジェクトのプロパティとしてイベントハンドラが設定されている場合はここで実行される

- バブリングフェーズ

イベントターゲットからDOMツリーをたどっていくフェーズ。
イベントによってはパブリングしない(例:focus)


##キャンセル　Event.stopPropagation()メソッド

- イベントを伝播させないようにする
https://developer.mozilla.org/ja/docs/Web/API/Event/stopPropagation

- 標準処理のキャンセル
https://developer.mozilla.org/ja/docs/Web/API/Event/preventDefault


#独自イベント

標準として定義されているイベント以外に、独自でイベントを定義して発火することができる。

- createEvent()メソッドでイベントオブジェクトを生成する。
- そのイベントオブジェクトを対象となるノードのdispatchEvent()メソッドでディスパッチする。
- 対象となるノードに設定されたイベントハンドラ/イベントリスナが呼び出される。

```独自イベント.js

var event = document.createEvent('Event');//イベントオブジェクトを生成
event.initEvent('myevent', true,true); //イベントタイプを指定
var target = document.getElementById('foo');
target.addEventListener('myevent', function(){
　alert('fired');
}, false);
target.dispatchEvent(event);

```
- dispatchEvent()メソッドは対応するイベントリスナの返り値を返す。

※IEの場合
createEvent()メソッド、dispatchEvent()メソッドの代わりに、
createEventObject()メソッド、fireEvent()を使う。


##setTimeout()メソッドを利用すれば、dispatchEvent()を非同期で実行できる

```js

window.setTimeout(function (){
　target.dispatchEvent(event);
},10);
```