【Vue.js】Vue.Draggableを使ってドラッグ&ドロップで並べ替えをする表をつくる方法メモ
2018-02-15
こんな感じでドラッグ&ドロップでソートが出来る表を作りますよー。もちろん、スマホなどのタッチパネルにも対応しています。
※2018年2月15日追記:Edgeでも使用する場合、オプションに「forceFallback:true
」を追記しないと、動かなかったりすることが判明したので後述します。
準備
まずは、npmでインストールをします
1 |
npm install vuedraggable --save-dev |
次にVue.jsのmain.js(app.js)に以下の記載をし、Vue.Draggableを使用可能な状態にしておきます
1 |
import draggable from 'vuedraggable' |
template
ソート可能にしたいリストをコンポーネントでラップします。
draggableはv-modelディレクティブを使用することが可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<template> ・ ・ ・ <draggable v-model="subTaskList"> <sub-task-area v-for = "(subTask, index, key) in subTaskList" class = "list-group-item" :subTask = "subTask" :index = "index" :key = "key" > </sub-task-area> </draggable> ・ ・ </template> <script> Vue.component('draggable', require('vuedraggable')); //★コンポーネントとしてrequireしておくこと ・ ・ |
※今回はタスク画面に表示するサブタスクリストの一覧をソートしたいので、子コンポーネント(sub-task-area)を ラップしています。
なんと、コレだけでv-forで展開したリストを好きなようにドラッグ&ドロップすることができます!しかも変更はv-modelした配列に反映されます。
Vuexを使用している場合
Vuexを使用している場合は、配列をcomputedで取得しているケースがほとんどなので、ソートが反映されません。
ミューテーションにコミットし、Vuex のストアの状態を変更してあげる必要があります。
具体的には、getterを使用し、set時に変更された配列をコミットします。(valに変更された配列がセットされています。)
1 2 3 4 5 6 7 8 9 10 |
computed: { subTaskList:{ get() { return store.getters.subTaskList; }, set(val) { store.commit('setsubTaskLists', val); } }, }, |
アニメーションをつける場合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<draggable v-model="subTaskList" v-bind:options="{ animation: 200, //アニメーション delay: 50 //スクロール防止(長押しでソート) }" > <sub-task-area v-for = "(subTask, index, key) in subTaskList" :subTask = "subTask" :index = "index" :key = "key" > </sub-task-area> </draggable> |
オプションを使用することで、トップに載せたようにヌルヌル動くアニメーションを簡単に付与することができます。
また、スマホでスクロール(フリック?スワイプ?)する事を想定してdelay(遅延)をつけておくと、スクロールしようとしたのに、ドラッグになってしまう!という事が起きにくいと思います。
以下のようにhandleオプションを使ってドラッグ対象の要素をCSSセレクタで指定する方法もあります。(こっちの方が使い勝手いいかな。)
1 2 3 4 5 6 7 8 9 10 |
<draggable v-model="categoryList" v-bind:options="{ animation: 200, delay: 50, handle:'.handle' //★コレ }" @sort="sortList" class="draggable" > |
イベント発火させたい場合
同じくイベント発生時の挙動を指定したい場合は、v-onにて設定することができます。
1 2 3 4 5 |
<draggable v-model="list" v-on:start="listDragBegin" @sort="listSort" > |
optionとイベントはこちらを見ると全部載ってます。
draggableタグがdivになってしまうのウザい場合
draggableタグはブラウザでレンダリングされた際、divとして表示されてしまいます。
テーブルで使う時は<tbody>タグになってもらわないと、デザインが崩れてしまい厄介です。
そんな時は以下のように、:elementで要素指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<draggable :element="'tbody'" //★コレ v-model="list" v-bind:options="{ animation: 200, delay: 50, handle:'.-reorder' }" @sort="sortList" > <tr v-for = "(data, index, key) in list"> <td class="col-buttons -reorder"><i class="fa fa-2x fa-reorder"></i></td> <td>{{data.name}}</td> <td>{{data.info}}</td> <td class="col-buttons"> <a class="btn btn-primary btn-xs" @click.prevent="showData(data.id)"> <i class="fa fa-angle-double-right">詳細</i> </a> </td> </tr> </draggable> |
EdgeでVue.Draggableが動かなくて悲しい場合
検証用のWindowsが古かったせいかもしれませんが、Edgeで、ソートが出来ない事象が発生しました。
その時は、オプションに「forceFallback:true
」を追記しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<draggable :element="'tbody'" v-model="list" v-bind:options="{ animation: 200, forceFallback:true, //★コレ delay: 50, handle:'.-reorder' }" @sort="sortList" > <tr v-for = "(data, index, key) in list"> <td class="col-buttons -reorder"><i class="fa fa-2x fa-reorder"></i></td> <td>{{data.name}}</td> <td>{{data.info}}</td> <td class="col-buttons"> <a class="btn btn-primary btn-xs" @click.prevent="showData(data.id)"> <i class="fa fa-angle-double-right">詳細</i> </a> </td> </tr> </draggable> |
このオプションを入れることで、最新の HTML5 のドラッグ アンド ドロップ モデルを無視して従来のドラッグ アンド ドロップモデルを呼び出してくれるそうです。
その結果、古いブラウザでも同じ挙動が期待できるらしいのですが、この修正を入れた後は、再度、サポートすべきブラウザ全てで動作確認をやり直したほうがよさそうですね。(特にiphoneのsafariとか)
また、ドラッグ中のCSSの当たり方が狂ったりするので、Bootstrapライブラリーのモーダルなど、CSSが複雑に絡み合っているDOM上では使わないほうがいいかもです。(なるべくシンプルなモーダルの中で使うとか。)
ちなみに私の場合は、「forceFallback:true
」を追記したら、Edgeのみ「animation: 200」オプションが効かなくなりました。
<tr>ではなく、<li>タグでVue.Draggableを使用しているプロジェクトでは、Edgeでもアニメーションのオプションが効いていたので、Edge+<table>タグを組み合わせている場合はアニメーションは諦めたほうが、無駄な工数がかからなさそうかな。(Sortable.jsをちゃんと調査しないと、なんとも言えませんが・・。)
何はともあれVue.Draggableは素晴らしい!
最初はjQuery UIのSortableを使おうとして、最後の最後にスマホ対応していないことに気づき、次にvue-sortableを試してたらVue2.0だと上手く動かず、かなり苦戦していたのですが、Vue.Draggableを使用したらかなり簡単に実装することができました!
教えてくれた会社の先輩方に感謝!
この記事がお役に立てたら、是非シェアをお願いします^^