などの疑問や悩みを解決してまいります。
ドラッグ&ドロップを実装したいものの、「実装に時間がかりそう」「難しそう」などイメージを持っている方も多いのではないでしょうか。
今回はVue.draggable.nextというVueプラグインを使用して、ドラッグ&ドロップを簡単に実装する方法と使い方について解説します。
Vue.draggable.nextとは
Vue.draggable.nextとは、Vue.jsを用いたプロジェクトでドラッグ&ドロップを実装するためのプラグインです。
Vue.draggable.nextはSortable.jsを元に作られているため、Vue.draggable.nextの公式ページに記載がなくてもSortable.jsの公式ページに記載がある内容も使用できます。
このプラグインを使用することで簡単にドラッグ&ドロップを実装することができます。
実装方法について
それではVue.draggable.nextの実装方法と、数ある機能のうちいくつかをご紹介していきます。
インストール
まずはプロジェクトにVue.draggable.nextをインストールします。
VSCodeでターミナルを開き、以下のコマンドを入力します。
npm i -S vuedraggable@next
入力しましたら、以下のようにインストールが実行されます。
インストールが完了しましたら、App.vueに以下のように記述します。
<script setup lang="ts">
import { ref } from 'vue'
import draggable from 'vuedraggable'
const peopleData = ref([
{ name: 'tanaka', id: 0 },
{ name: 'suzuki', id: 1 },
{ name: 'sato', id: 2 },
{ name: 'mori', id: 3 },
{ name: 'takago', id: 4 }
])
</script>
<template>
<v-container>
<v-row>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData" group="people" item-key="id">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataデータの中身:{{ peopleData }}</div>
</v-col>
</v-row>
</v-container>
</template>
※上記コードはVuetifyを使用しています。コピペする場合は別途Vuetifyをインストールして下さい!
Vuetifyのインストール方法は以下にありますのでぜひ参考にしてください。
-
【Vuetify3】Vuetifyの導入方法について解説します。
続きを見る
上記コードで以下のように実装ができると思います。
<template #item="{ element }">の名称変更
element
の部分は以下のように:
で名称を変更することができます。
<template #item="{ element: element2 }">
コンポーネント間の移動
ドラッグ&ドロップ1番の目玉機能はやはりコンポーネント間の移動です。
移動させたいコンポーネントのdraggable
タグにgroup
を指定します。
<script setup lang="ts">
import { ref } from 'vue';
import draggable from 'vuedraggable';
const peopleData = ref([
{ name: 'tanaka', id: 0 },
{ name: 'suzuki', id: 1 },
{ name: 'sato', id: 2 },
{ name: 'mori', id: 3 },
{ name: 'takago', id: 4 }
]);
const peopleData2 = ref([]);
</script>
<template>
<v-container>
<v-row>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData" group="people" item-key="id">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataデータの中身:{{ peopleData }}</div>
</v-col>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData2" group="people" item-key="id">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataの中身:{{ peopleData2 }}</div>
</v-col>
</v-row>
</v-container>
</template>
以下のようにコンポーネント間を移動できるようになればOKです。
ドラッグ、ドロップ時にイベント処理
ドラッグ、ドロップ時それぞれにイベント処理を発生させたい場合はドラッグ時は@start
、ドロップ時は@end
を使用します。
<script setup lang="ts">
import { ref } from 'vue'
import draggable from 'vuedraggable'
const peopleData = ref([
{ name: 'tanaka', id: 0 },
{ name: 'suzuki', id: 1 },
{ name: 'sato', id: 2 },
{ name: 'mori', id: 3 },
{ name: 'takago', id: 4 }
])
const peopleData2 = ref([])
// コンソールで実行確認
const testStart = () => {
console.log('ドラッグ時に実行')
}
const testEnd = () => {
console.log('ドロップ時に実行')
}
</script>
<template>
<v-container>
<v-row>
<v-col>
<v-list :border="true" class="pa-8">
<draggable
v-model="peopleData"
group="people"
item-key="id"
@start="testStart"
@end="testEnd"
>
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataデータの中身:{{ peopleData }}</div>
</v-col>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData2" group="people" item-key="id">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataの中身:{{ peopleData2 }}</div>
</v-col>
</v-row>
</v-container>
</template>
以下のようにコンソールに表示されればOKです。
順番の入れ替え
コンポーネント内で順番の入れ替えの可否はsort
プロパティで設定ができます。
boolean値で可否が設定でき、デフォルトはtrue
なので入れ替えができるようになっていますが、false
にすると入れ替えができなくなります。
<script setup lang="ts">
import { ref } from 'vue'
import draggable from 'vuedraggable'
const peopleData = ref([
{ name: 'tanaka', id: 0 },
{ name: 'suzuki', id: 1 },
{ name: 'sato', id: 2 },
{ name: 'mori', id: 3 },
{ name: 'takago', id: 4 }
])
const peopleData2 = ref([])
</script>
<template>
<v-container>
<v-row>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData" group="people" item-key="id" :sort="false">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataデータの中身:{{ peopleData }}</div>
</v-col>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData2" group="people" item-key="id" :sort="false">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataの中身:{{ peopleData2 }}</div>
</v-col>
</v-row>
</v-container>
</template>
以下のように順番の入れ替えができなくなればOKです。
ドラッグ&ドロップの可否設定
要素をドラッグ&ドロップできなくする場合は、:disabled
を使用します。
<script setup lang="ts">
import { ref } from 'vue'
import draggable from 'vuedraggable'
const peopleData = ref([
{ name: 'tanaka', id: 0 },
{ name: 'suzuki', id: 1 },
{ name: 'sato', id: 2 },
{ name: 'mori', id: 3 },
{ name: 'takago', id: 4 }
])
const peopleData2 = ref([])
</script>
<template>
<v-container>
<v-row>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData" group="people" item-key="id" :sort="false" :disabled="true">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataデータの中身:{{ peopleData }}</div>
</v-col>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData2" group="people" item-key="id" :sort="false">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataの中身:{{ peopleData2 }}</div>
</v-col>
</v-row>
</v-container>
</template>
上記の例ではpeopleData
に:disabled
を設定しています。
boolean値でドラッグ&ドロップの可否を設定でき、デフォルトはtrue
です。
移動したタイミングでイベント発生
@end
はドロップしたタイミングでイベントを発生させますが、Move
を使用することでドラッグした要素がリスト内、または異なるリスト間を移動したタイミングでイベントを発生させることできます。
// 処理省略
const testConsole = () => {
console.log('移動時にイベント発生')
}
</script>
<template>
<v-container>
<v-row>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData" group="people" item-key="id" :sort="false" :move="testConsole">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataデータの中身:{{ peopleData }}</div>
</v-col>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData2" group="people" item-key="id" :sort="false">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataの中身:{{ peopleData2 }}</div>
</v-col>
</v-row>
</v-container>
</template>
リスト内、または別のリストにドラッグするとイベント処理が実行されているのが分かるかと思います。
選択した要素にクラスを付与
選択したドラッグ要素に対してクラスを付与することができるのが、chosenClass
です。
<template>
<v-container>
<v-row>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData" group="people" item-key="id" chosenClass="bg-red">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataデータの中身:{{ peopleData }}</div>
</v-col>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData2" group="people" item-key="id" chosenClass="bg-blue">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataの中身:{{ peopleData2 }}</div>
</v-col>
</v-row>
</v-container>
</template>
<style scoped>
.bg-red {
background-color: #e53935;
}
.bg-blue {
background-color: #35a4e5;
}
</style>
選択時にクラスが付与され、ドラッグしている間も背景色が付与されます。
移動時にクラス付与
dragClass
を指定することで、ドラッグして移動している間に限りクラスを付与することもできます。
<template>
<v-container>
<v-row>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData" group="people" item-key="id" :sort="false" dragClass="bg-red">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataデータの中身:{{ peopleData }}</div>
</v-col>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData2" group="people" item-key="id" :sort="false">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataの中身:{{ peopleData2 }}</div>
</v-col>
</v-row>
</v-container>
</template>
<style scoped>
.bg-red {
background-color: #e53935;
}
.bg-blue {
background-color: #35a4e5;
}
</style>
chosenClass
のときは選択時と移動時も背景色が変更されていることを確認できたと思いますが、dragClass
だと選択時は背景色が変わらず、移動時のみクラスが付与されていることが分かります。
指定したリスト内に移動したタイミングでクラス付与
ghostClass
をリストに指定することで、その指定したリスト内に移動したタイミングでドラッグ要素に対してクラスを付与することができます。
<template>
<v-container>
<v-row>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData" group="people" item-key="id" :sort="false" ghostClass="bg-red">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataデータの中身:{{ peopleData }}</div>
</v-col>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData2" group="people" item-key="id" :sort="false">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataの中身:{{ peopleData2 }}</div>
</v-col>
</v-row>
</v-container>
</template>
<style scoped>
.bg-red {
background-color: #e53935;
}
.bg-blue {
background-color: #35a4e5;
}
</style>
以下のように、左のリスト内でドラッグを開始したときは背景が赤になり、右側のリスト内に移動したときは青色に変化していることが分かります。
ドラッグ&ドロップの要素の移動をスムーズにする
animation
を指定することで、リスト内の要素の移動をスムーズにすることができます。
<template>
<v-container>
<v-row>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData" group="people" item-key="id" :sort="false" :animation="300">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataデータの中身:{{ peopleData }}</div>
</v-col>
<v-col>
<v-list :border="true" class="pa-8">
<draggable v-model="peopleData2" group="people" item-key="id" :sort="false">
<template #item="{ element: element2 }">
<v-list-item :border="true" class="pa-8 mt-4">
{{ element2.id }}. {{ element2.name }}
</v-list-item>
</template>
</draggable>
</v-list>
<div>peopleDataの中身:{{ peopleData2 }}</div>
</v-col>
</v-row>
</v-container>
</template>
以下のように要素の入れ替えの動きが滑らかになったのが分かるかと思います。
まとめ
ここまで読んでいただきありがとうございました。
本記事のまとめです。
ポイント
- Vue.draggable.nextは、Vue.jsを用いたプロジェクトでドラッグ&ドロップを実装するためのプラグイン
element
の部分は:
で区切り、名称を変更することができる- 移動させたいコンポーネントの
draggable
タグにgroup
を指定 - ドラッグ、ドロップ時それぞれにイベント処理を発生させたい場合はドラッグ時は
@start
、ドロップ時は@end
を指定 - コンポーネント内で順番の入れ替えの可否は
sort
プロパティで設定 - 要素をドラッグ&ドロップできなくする場合は、
:disabled
を指定 Move
を使用することでドラッグした要素がリスト内、または異なるリスト間を移動したタイミングでイベントを発生させることできるchosenClass
を指定することで、選択したドラッグ要素に対してクラスを付与することができるdragClass
を指定することで、ドラッグして移動している間に限りクラスを付与することができるghostClass
を指定することで、その指定したリスト内に移動したタイミングでドラッグ要素に対してクラスを付与することができるanimation
を指定することで、リスト内の要素の移動をスムーズにすることができる