JavaScript で ドラッグ＆ドロップをやってみる

JavaScript でドラッグ＆ドロップを簡単につくってみる
出来上がったやつのサンプルページのリンク、イメージはこんな感じ

https://sueasen.github.io/javascript-exercise/work/dragdrop/

<p class="codepen" data-height="200" data-default-tab="html,result" data-slug-hash="yLQyPNp" data-user="sueasen" style="height: 200px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sueasen/pen/yLQyPNp">
  Untitled</a> by sueasen (<a href="https://codepen.io/sueasen">@sueasen</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


# ドラッグ＆ドロップ概要
やることとしては以下をする感じ
- ドラッグする対象の `draggable` を `true` にする
- ドラッグする対象に `dragstart` のイベントを追加する
- ドロップする対象に `drop`, `dragenter`, `dragleave`, `dragover` のイベントを追加する
- `event.dataTransfer` の `setData`, `getData` でドラッグする情報の受け渡しをする

# ドラッグ＆ドロップのイベント概要
サンプルで使ってるやつだけ．．．

## ドラッグするタグに設定するイベント

### `dragstart` ドラッグ開始時イベント
`event.dataTransfer.setData("text", event.currentTargetより取得する値)` でドラッグする情報が設定できる
`event.dataTransfer.setDate` の第一引数にデータ形式(型)を設定, オブジェクト(HTMLElement) とかは設定できなそう．．．

## ドロップするタグに設定するイベント

### `drop` : ドロップ時イベント
`event.dataTransfer.getData("text")` でドラッグ時に設定した値を取得
ドラッグ開始時に設定したときの第一引数のデータ形式と同じ値を引数にする

### `dragenter` ： ドラッグしながらドロップ対象に入ってきた時のイベント
`event.currentTerget` でドロップ対象がとれる

### `dragleave` ： ドラッグしながらドロップ対象を出た時のイベント
`event.currentTerget` でドロップ対象がとれる

### `dragover` ： ドラッグしながらドロップ対象の上にいる時のイベント
`event.preventDefault()` でイベントをキャンセルする
キャンセルしないと定期的にイベント発生して `drop` が発火しない（しずらいだけかも．．．）

# サンプルコード
## HTML
```HTML
<!doctype html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="stylesheet" href="./style.css">
</head>

<body>
    <h3>ドラッグ＆ドロップ</h3>
    <div class="flex-row">
        <div id="1" class="box drag">どらっぐ1</div>
        <div id="2" class="box drop">どろっぷ1</div>
        <div id="3" class="box drop">どろっぷ2</div>
        <div id="4" class="box drop">どろっぷ3</div>
    </div>
    </div>
</body>

<script src="script.js"></script>

</html>
```

## JavaScript
```JavaScript

// drag 設定
document.querySelector(".box.drag").draggable = true;
document.querySelector(".box.drag").addEventListener("dragstart", onDragStart);

// drop 設定
document.querySelectorAll(".box.drop").forEach((element) => {
    element.addEventListener("drop", onDrop);
    element.addEventListener("dragover", onDragover);
    element.addEventListener("dragenter", onDragenter);
    element.addEventListener("dragleave", onDragleave);
});

/**
 * ドラッグ処理
 * @param {Event} event 
 */
function onDragStart(event) {
    event.dataTransfer.setData("text", event.currentTarget.id);
}

/**
 * ドロップ処理
 * @param {Event} event 
 */
function onDrop(event) {
    event.currentTarget.classList.remove("dragging");
    const boxs = [...document.querySelectorAll(".box")];
    if (boxs.indexOf(event.currentTarget) === 0) {
        event.currentTarget.before(document.getElementById(event.dataTransfer.getData("text")));
    } else {
        event.currentTarget.after(document.getElementById(event.dataTransfer.getData("text")));
    }
}

/**
 * 操作が要素上に入ってきたとき
 * @param {Event} event 
 */
function onDragenter(event) {
    event.currentTarget.classList.toggle("dragging");
}

/**
 * 操作が要素上から出たとき
 * @param {Event} event 
 */
function onDragleave(event) {
    event.currentTarget.classList.toggle("dragging");
}

/**
 * 操作が要素上を通過してるとき
 * @param {Event} event 
 */
function onDragover(event) {
    event.preventDefault();
}
```

## CSS
```CSS
@charset "utf-8";

body {
  text-align: center;
}

.flex-row {
  display: flex;
  justify-content: center;
}

.box {
  line-height: 80px;
  height: 80px;
  width: 80px;
  border: 1px solid gray;
}

.box.drag {
  background-color: skyblue;
}

.box.dragging {
  background-color: skyblue;
  opacity: 0.5;
}

```