---
# System prepended metadata

title: Vue.js で Drug&Drop API 使うメモ
tags: [vue]

---

###### tags: `vue`

# Vue.js で Drug&Drop API 使うメモ

[Vue Mastery](https://www.vuemastery.com/courses) でDrug&Drop APIについて扱っていたので、忘れないようにメモ

## Drug&Drop API

[HTML ドラッグ＆ドロップ API](https://developer.mozilla.org/ja/docs/Web/API/HTML_Drag_and_Drop_API)を参照

[draggable](https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/draggable) 属性に対してドラッグイベントを発生させることができる
ドロップ関連のイベントなどを含めると

* dragstart
* dragend
* dragover
など...

```htmlmixed
<p id="p1" draggable="true">この要素はドラッグできます。</p>
```

## Vueで作用させる

下記の点を記述する、素のjavascriptより簡潔にできる印象
不要なイベントは、デフォルトの処理が発火してしまうので`prevent`で抑制させる

* Drag したい要素
    * `draggable`属性を付与
    * `dragstart`イベントをv-onで設定
    (.self は、イベント対象が自身の場合作用させるイベント修飾子)
* Drap したい要素
    * `drop`イベントをv-onで設定

```htmlmixed
<template>
  <div>
    <p
      id="p1"
      draggable="true"
      @dragstart.self="onDrag"
      @dragover.prevent
      @dragenter.prevent
    >
      この要素はドラッグできます。
    </p>
    <p
      id="p2"
      @drop.stop="onDrop"
      @dragover.prevent
      @dragenter.prevent
    >
      この要素にドロップできます。
    </p>
</div>

</template>

<script>
export default {
  mehtods: {
    onDrag (event) {
      // Drug イベント処理を記述
    },
    onDrop (event) {
      // Drop イベント処理を記述
    }
  }
}
</script>
```
:::warning
(※) Vuetify のようなコンポーネントに作用させる場合、ドキュメントに記載されたイベントトリガーに合わせて設定させる
:::

## Drag&Drop処理関連

[DataTransfer](https://developer.mozilla.org/ja/docs/Web/API/DataTransfer) APIを使用することで、Drag&Drop時の処理を行える


* DataTransfer.dropEffect: エフェクト関連
* DataTransfer.effectAllowed: 操作の許可
* DataTransfer.files: ファイル関連
* DataTransfer.getData(): DataTransfer内の指定されたデータを取得
* DataTransfer.setData(): DataTransfer内に指定したデータを設定

## コンポーネント化

汎用的に使える用にベースコンポーネント化

### AppDrug.vue
---

```htmlmixed=
<template>
  <div
    draggable
    @dragstart.self="onDrag"
    @dragover.prevent
    @dragenter.prevent
  >
    <slot />
  </div>
</template>

<script>
export default {
  props: {
    transferData: {
      type: Object,
      required: true,
      default: () => {}
    }
  },
  methods: {
    onDrag (e) {
      e.dataTransfer.effectAllowed = 'move'
      e.dataTransfer.dropEffect = 'move'

      e.dataTransfer.setData('payload', JSON.stringify(this.transferData))
    }
  }
}
</script>
```
### AppDrop.vue
---

```htmlmixed=
<template>
  <div
    @drop.stop="onDrop"
    @dragover.prevent
    @dragenter.prevent
  >
    <slot />
  </div>
</template>

<script>
export default {
  methods: {
    onDrop (e) {
      const transferData = JSON.parse(e.dataTransfer.getData('payload'))
      this.$emit('drop', transferData)
    }
  }
}
</script>

```
### ベースコンポーネント使用例
---

`transferData`にオブジェクトをpropsし、Drag&Dropを行う

```htmlmixed=
<template>
  <AppDrop @drop="moveTaskOrColumn">
    <AppDrag
      class="task"
      :transferData="{
        type: 'task',
        fromColumnIndex: columnIndex,
        fromTaskIndex: taskIndex
      }"
      @click.native="goToTask(task)"
    >
      <span class="w-full flex-no-shrink font-bold">
        {{ task.name }}
      </span>
      <p v-if="task.description" class="w-full flex-no-shrink mt-1 xt-sm">
        {{ task.description }}
      </p>
    </AppDrag>
  </AppDrop>
</template>
```

以上!
