JavaScriptのイベント

## イベントリスナー

### イベントリスナーの追加

```:js
イベントターゲット.addEventListener(イベント名,リスナー,[オプション])
```

### イベントリスナーの削除

```:js
removeEventListener(イベント名,リスナー,[オプション])
```

### イベントリスナーを一度だけ呼び出す

|addEventListenerのオプション|内容|
|---|---|
|capture|キャプチャーフェーズで取得するかどうか(真偽値)|
|once|リスナーの呼び出しを一回にするか(真偽値)|
|passive|パッシブイベントかどうか(真偽値)|

### イベントの情報自体を取得する
#### MouseEventなどイベント自体の情報を取得する
eventは任意の文字列です。

```:js
button.addEventListener("click",(event)=>{
  console.log(event);
})
```

### イベントが発生した要素を取得する
eventは任意の文字列です。

```:js
button.addEventListener("click",(event)=>{
  console.log(event.tareget);
})
```


```:js
//オプション指定
const option = {
  once: true
}
 
const clickAlart = () => {
  alert("クリックされた");
}

const button = document.querySelector("button");
button.addEventListener("click", clickAlart, option)
```




## クリックイベント

|イベント|内容|
|---|---|
|click|左ボタンシングルクリック|
|dblclick|左ボタンダブルクリック|
|contextmenu|右ボタンクリック|
|mousedown|マウスのボタンを押した時|
|mouseup|マウスのボタンを離した時|

```:html
<button>ボタン</button>
```

```:js
const button = document.querySelector("button");
  button.addEventListener("click",()=>{
  console.log("クリックされた");
})
```




## マウスイベント(クリックイベント以外)

|イベント|内容|
|---|---|
|mousemove|対象エリア内でマウスを動かした時|
|mouseenter|対象エリアにカーソルが入った時|
|mouseleave|対象エリアからカーソルが出た時|
|mouseover|対象エリアにカーソルが入った時(バブリングあり)|
|mouseout|対象エリアからカーソルが出た時(バブリングあり)|
|mousewheel|マウスホイールを回転させた時|

バブリング：イベントが親要素や先祖要素に伝わることです。


```:js
対象エリア.addEventListener("mousemove",()=>{
 message.innerHTML="マウスが動いた";}
)
```

```:html
<div class="target""></div>
<p class="message"></p>
```

```:css
.target {
  height: 100px;
  background-color: red;
}
```

```:js
const message = document.querySelector(".message");

const target = document.querySelector(".target");

target.addEventListener("mousewheel", () => {
  message.innerHTML = "赤い領域内でマウスホイールが動いた";
})
``` 

### マウスの座標を取得

|マウスの座標|内容|
|---|---|
|event.clientX|ブラウザ左上を基準としたX座標|
|event.clientY|ブラウザ左上を基準としたY座標|
|event.offsetX|要素左上を基準としたX座標|
|event.offsetY|要素左上を基準としたY座標|
|event.pageX|ページ左上を基準としたX座標|
|event.pageY|ページ左上を基準としたY座標|
|event.screenX|画面左上を基準としたX座標|
|event.screenY|画面左上を基準としたY座標|

```:js
対象エリア.addEventListener("mousemove",(event)=>{
  console.log(event.clientX,event.clientY);
});
```

```:html
<div class="target"></div>
```

```:css
.target {
  height: 100px;
  background-color: red;
}
```

```:js
//ターゲットの領域を取得
const target = document.querySelector(".target");

//ターゲットの領域内でマウスカーソルが動くたびに座標を表示
target.addEventListener("mousemove", (event) => {
  console.log(event.clientX, event.clientY);
})
```

## タッチイベント

|イベント|内容|
|---|---|
|touchstart|タッチ開始時|
|touchmove|タッチポイント移動時|
|touchend|タッチ終了時|



```:html
<p class="target"></p>
<p class="message"></p>
```

```:css
.target {
  height: 100px;
  background-color: red;
}
```

```:js
const text = document.querySelector(".target");
const message = document.querySelector(".message");

text.addEventListener("touchstart", () => {
    message.innerHTML = "タッチ開始";
});
text.addEventListener("touchmove", () => {
    message.innerHTML = "タッチムーブ";
});

text.addEventListener("touchend", () => {
    message.innerHTML = "タッチ終了";
});
```

### タッチイベントの情報を取得する

|プロパティ|内容|
|---|---|
|changedTouches|タッチ情報の配列|
|clientX|ブラウザ左上基準のX座標|
|clientY|ブラウザ左上を基準としたY座標|
|offsetX|要素左上を基準としたX座標|
|offsetY|要素左上を基準としたY座標|
|pageX|ページ左上を基準としたX座標|
|pageY|ページ左上を基準としたY座標|
|screenX|画面左上を基準としたX座標|
|screenY|画面左上を基準としたY座標|

|タッチイベントとマウスイベントの違い|内容|
|---|---|
|タッチイベント|複数同時に起こる場合がある|
|マウスイベント|複数同時に起こらない|


```:html
<p class="target"></p>
<p class="message"></p>
```

```:css
.target {
  height: 100px;
  background-color: red;
}
```

```:js
const target = document.querySelector(".target");
const message = document.querySelector(".message");

target.addEventListener("touchmove", () => {
  const touch = event.changedTouches;

  message.innerHTML = `${touch[0].pageX.toFixed(2)}<br>${touch[0].pageY.toFixed(2)}`;
    
});
```
toFixed(2)で小数点第2位までになるように四捨五入しています。



## テキスト選択時

|イベント|内容|
|---|---|
|selectstart|テキスト選択開始時|

```:html
<p class="text">ああああああああああああああ</p>
```

```:js
//ターゲットの取得
const text = document.querySelector(".text");
 
text.addEventListener("selectstart", () => {
             
  console.log("文字列の選択が開始された");
 
});
```


## キーボードイベント

|イベント|内容|
|---|---|
|keydown|キーが押された時|
|keypress|キーが押された時(文字キーのみ=修飾キー以外)|
|keyup|キーが離された時|

1つのキーを押して離した時、keydown→keypress→keyupの順番に発生します。

```:html
<textarea></textarea>
```

```:html
const textarea = document.querySelector("textarea");
        
textarea.addEventListener("keypress", () => {
 
  console.log("キーが押された");
 
});
```

### 入力されたキーを判定する

|プロパティ|内容|
|---|---|
|key|ボタンの値|
|keyCode|ボタンのコード|
|code|キーの名前|
|repeat|キーを押しっぱなしにしているかどうか(真偽値)|
|isComposing|入力が未確定かどうか(真偽値)|

```:html
<textarea></textarea>
```

```:js
const textarea = document.querySelector("textarea");


const keytype1 = (event) => {
  console.log(`値：${event.key}`);
  console.log(`コード：${event.keyCode}`);
  console.log(`名前：${event.code}`);
  console.log(`未確定?：${event.isComposing}`);

  console.log(`alt?：${event.altkey}`);
}

textarea.addEventListener("keyup", keytype1)


const keytype2 = (event) => {
  console.log(`押しっぱなし?：${event.repeat}`);
}

textarea.addEventListener("keydown", keytype2)
```




## イベントを発火させる

|メソッド|内容|
|---|---|
|dispatchEvent(イベント)|イベントを発生させる|
|```new Event("イベント名",[{detail:値}])```|イベントを生成する|

### クリックしなくても、3秒後にクリックイベントを発火させる

```:html
<p class="target"></p>
```

```:js
const target=document.querySelector(".target");
target.addEventListener("click",()=>{
  target.innerHTML="クリックされた";
});

setTimeout(()=>{
  target.dispatchEvent(new Event("click"));
},3000);
```

## デフォルトのイベントをキャンセルする

|メソッド|内容|
|---|---|
|preventDefault()|イベントのデフォルトの挙動をキャンセル|


### マウスホイールを無効化

```:js
document.querySelector(".target").addEventListener("wheel",(event)=>{
  event.preventDefault();
})
```

### タッチ開始を無効化

```:js
document.querySelector(".target").addEventListener("touchstart",(event)=>{
  event.preventDefault();
})
```

## ドラッグ&ドロップ

|ドラッグする要素のイベント|内容|
|---|---|
|dragstart|要素のドラッグ開始時|
|drag|ドラッグしている時|
|dragend|ドラッグ終了時|

|ドラッグを受ける要素のイベント|内容|
|---|---|
|dragenter|ドラッグしながら要素に入った時|
|dragover|ドラッグしながら要素に存在するとき|
|dragleave|ドラッグしながら要素から出た時|
|drop|要素をドロップしたとき|



|ドラッグのイベント情報|内容|
|---|---|
|event.dataTransfer.files|ドロップされたファイル情報|

```:html
<div id="startArea">
  <div id="target" draggable="true">
    <p id="targetword">Drag me!</p>
  </div>
</div>

<div id="goalArea">
</div>
```

```:css
body {
  position: relative;
}
 
#target {
  width: 98px;
  height: 98px;
  background-color: darkcyan;
  border: solid 1px #000;
  box-sizing: border-box;
}
 
#targetword {
  width: 100px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-weight: bold;
  margin: 0;
}

#startArea {
  width: 100px;
  height: 100px;
  margin: 10px 0;
  border: solid 1px black;
  position: fixed;
  top: 10px;
  left: 10px;
  box-sizing: border-box;
}
 
#startword {
  display: flex;
  align-items: center;
  justify-content: center;
  color: orange;
  font-weight: bold;
  width: 100px;
  height: 100px;
  margin: 0;
}

#goalArea {
  width: 100px;
  height: 100px;
  margin: 10px 0;
  border: solid 1px black;
  position: fixed;
  bottom: 10px;
  right: 10px;
  box-sizing: border-box;
}

.dragging {
  display: none;
}

.dragged {
  background-color: orange;
}
```

```:js
//ターゲットの取得
const target = document.querySelector('#target');

//スタートエリアの取得
const startArea = document.querySelector('#startArea');

//ゴールエリアの取得
const goalArea = document.querySelector('#goalArea');

//ターゲットのドラッグが開始された時
target.addEventListener('dragstart', () => {
  console.log("dragstartイベント");
});

//ドラッグ中の時
target.addEventListener('drag', () => {
  console.log("dragイベント");

　　//ターゲットを非表示にする
　　target.classList.add("dragging");

});

//ドラッグが終了した時
target.addEventListener('dragend', () => {
  console.log("dragendイベント");

  //ターゲットを表示にする
  target.classList.remove("dragging");

});


//スタートエリアに入った時
startArea.addEventListener('dragenter', () => {
  console.log("dragenterイベント");

  //スタートエリアに色を着ける
  startArea.classList.add("dragged");

});

//ゴールエリアに入った時
goalArea.addEventListener('dragenter', () => {
  console.log("dragenterイベント");

  //ゴールエリアに色を着ける
  goalArea.classList.add("dragged");
});


//スタートエリアから離れた時
startArea.addEventListener('dragleave', (event) => {
  console.log("dragleaveイベント");

  //スタートエリアの背景色を戻す
  startArea.classList.remove("dragged");
  
});

//ゴールエリアから離れた時
goalArea.addEventListener('dragleave', (event) => {
  console.log("dragleaveイベント");

  //ゴールエリアの背景色を戻す
  goalArea.classList.remove("dragged");
  
});


//スタートエリア上にある時
startArea.addEventListener('dragover', (event) => {
  console.log("dragoverイベント");

  //dropの前処理
  event.preventDefault();
});

//ゴールエリア上にある時
goalArea.addEventListener('dragover', (event) => {
  console.log("dragoverイベント");

  //dropの前処理
  event.preventDefault();
  
  
});


//スタートエリアでドロップされた時
startArea.addEventListener('drop', () => {
  console.log("dropイベント");

  //ターゲットをスタートエリアに追加
  startArea.appendChild(target);
  
});

//ゴールエリアでドロップされた時
goalArea.addEventListener('drop', () => {
  console.log("dropイベント");

  //ターゲットをゴールエリアに追加
  goalArea.appendChild(target);
  
});
```

## 印刷

|イベント|内容|
|---|---|
|afterprint|印刷設定を閉じた時|
|beforeprint|印刷直前|

### 例：印刷時に印刷用クラスを適用する

```:html
<p class="normal" id="sample">Lorem, ipsum dolor sit amet consectetur adipisicing elit. Rerum doloribus ex nostrum sunt magni, itaque veniam sapiente provident velit quo vero, quaerat vitae porro cumque. Sunt dolore impedit saepe praesentium!</p>
```

```:css
.normal {
  color: red;
}
 
.print {
  color: blue;
}
```

```:js
const sample = document.querySelector("#sample");

window.addEventListener("afterprint", () => {

  //印刷用クラス削除
  sample.classList.remove("print");
            
});

window.addEventListener("beforeprint", () => {

  //印刷用クラス追加
  sample.classList.add("print");

});
```


## 読み込み完了

|イベント|内容|
|---|---|
|load|リソース含め全ての読み込み完了時|
|DOMContentLoaded|DOMツリーの構築完了時|

```:js
window.addEventListener("load", () => {
  console.log("ページ読み込み完了");
})
 
window.addEventListener("DOMContentLoaded", () => {
  console.log("DOMツリーが準備できた");
})
```

## 読み込みエラー

|イベント|内容|
|---|---|
|error|読み込み時にエラーが発生した時|

```:html
<img src="xxxxxxxxxxxxxxx.jpg">
```

```:js
const img = document.querySelector("img");
 
img.addEventListener("error", () => {
  console.log("画像表示エラー");
});
```