[[Vue]]でファイルをドラッグ&ドロップする場合のベーシックな実装方法。[[Tailwind CSS]]は利用するケースを想定。
> [!hint]
>
> ライブラリを使って並び替える方法は [[📰Vueで異なるモデルで構成された2つのリストをドラッグ&ドロップする方法の調査]] を参照。
## 想定ユースケース
以下のようなケースを想定。
- 特定エリアにドラッグすると色が変わる
- ドロップするとFileを受け取る
### VueUseを使わない
> [!caution]
> 特に理由がなければこのあとの[[#VueUseを使う]]方法を推奨する。
```html
<script setup lang="ts">
import { ref } from "vue";
const isDragOver = ref(false);
const handleDrop = (payload: DragEvent) => {
console.log(payload.dataTransfer?.files[0]);
};
const handleClickButton = (event: MouseEvent) => {
console.log(event.target);
};
</script>
<template>
<div class="flex justify-center items-center h-screen">
<div
class="size-192 text-4xl border-dashed border-2 border-gray-400 rounded-md p-12 transition duration-300"
:class="isDragOver ? ['bg-red-200'] : []"
@dragover.prevent
@dragenter="isDragOver = true"
@dragleave="isDragOver = false"
@drop.prevent="handleDrop"
>
<div
class="flex flex-col gap-4"
:class="{ 'pointer-events-none': isDragOver }"
>
<div>ここにドロップする</div>
<button
class="text-xl bg-blue-600 text-white p-2 rounded-lg hover:bg-blue-400 transition duration-300"
@click="handleClickButton"
>
ファイルを選択
</button>
</div>
</div>
</div>
</template>
```
## VueUseを使う
[[VueUse]]を使ってファイル選択ボタンの処理もちゃんと実装する。[[useDropZone]]と[[useFileDialog]]使う。
```html
<script setup lang="ts">
import { ref } from "vue";
import { useDropZone, useFileDialog } from "@vueuse/core";
const dropZoneRef = ref<HTMLDivElement>();
const { isOverDropZone } = useDropZone(dropZoneRef, {
onDrop: (files: File[] | null) => {
console.log(files?.[0]);
},
});
const { open: openFileDialog, onChange } = useFileDialog();
onChange((files) => {
console.log(files?.[0]);
});
</script>
<template>
<div class="flex justify-center items-center h-screen">
<div
ref="dropZoneRef"
class="size-192 text-4xl border-dashed border-2 border-gray-400 rounded-md p-12 transition duration-300"
:class="isOverDropZone ? ['bg-red-200'] : []"
>
<div class="flex flex-col gap-4">
<div>ここにドロップする</div>
<button
class="text-xl bg-blue-600 text-white p-2 rounded-lg hover:bg-blue-400 transition duration-300"
@click="
() => {
openFileDialog();
}
"
>
ファイルを選択
</button>
</div>
</div>
</div>
</template>
```