WEBアプリケーションでリッチなUIを実現したい場合、内部的には複雑な操作を簡単そうに見せるためのひとつの工夫として、Drag and Drop
は必須と言ってもいいと思います。
今回、Vue.jsとそのライブラリのVue.Draggableを利用して、簡単にリストのDrag and Drop
を実現することができたので、紹介したいと思います。
本エントリに記載しているソースコードは以下にあります。
デモ => https://zuckeym-17.github.io/vue-dnd/
Vue.Draggable
Vue.DraggableはSortable.jsというJavaScriptでリストの Drag and Drop
を実装するためのライブラリをベースに開発されています。
そのため、なにかやりたいなと思ったときは、Sortable.jsのドキュメントをあたったほうが、知りたかった情報が書かれていたりします。
例
Vueの基本的な説明は省略します。
画面の都合上、.vue
ファイルのstyleタグも省略しています。
また、コード中で利用しているListItem
というコンポーネントは、単なるリストの1要素です。
li
タグの中にspan
タグを配置し、ドラッグハンドルとして使っています。
<template> <!-- spanタグをドラッグハンドルとして利用、dragHandle Propsがtrueのときのみ現れる --> <li><span v-if="dragHandle" class="drag-handler">:::</span>{{ item }}</li> </template> <script> import Vue from "vue"; export default Vue.extend({ props: { item: String, dragHandle: false } }); </script>
1列のリスト
基本的な1列のリストを作成します。
Vue.Draggableをdraggable
でインポートして、element属性を変更しているだけです。
<template> <div style="margin: 50px;"> <p>1列リスト</p> <!-- Vue.Draggableのコンポーネントを利用。 ListItemは li なので、レンダリング時の要素を ul にするため element 属性を設定 --> <draggable element="ul"> <!-- list を v-for で 回す。 key属性については、 https://jp.vuejs.org/v2/guide/list.html#key を参照。 --> <list-item v-for="item in list" :key="list.indexOf(item)" :item="item"></list-item> </draggable> </div> </template> <script> import Vue from "vue"; import ListItem from "./ListItem"; import draggable from "vuedraggable"; // Vue.Draggableのコンポーネントをインポート export default Vue.extend({ components: { draggable, ListItem }, props: ["list"] }); </script>
与えられている list
は以下のようなものです。
const list = [ "トレイン=ハートネット", "スヴェン=ボルフィード", "イヴ", "リンスレット=ウォーカー" ];
複数列のリスト
複数列間でDrag and Drop
を実現します。
Vue.Draggable コンポーネントは、options属性にオブジェクトを渡すことで色々な設定ができます。
ここでは、group オプションを指定し、Drag and Drop
で要素を 複数列に渡って行き来させることができます。
<template> <div style="margin: 50px;"> <p>複数列リスト</p> <div style="display: flex"> <!-- options 属性に オブジェクトをbind board を v-for で 回す。 --> <draggable :options="options" element="ul" v-for="list in board" :key="board.indexOf(list)" > <!-- 1列リストのときと同様 --> <list-item v-for="item in list" :key="list.indexOf(item)" :item="item"></list-item> </draggable> </div> </div> </template> <script> import Vue from "vue"; import ListItem from "./ListItem"; import draggable from "vuedraggable"; export default Vue.extend({ components: { draggable, ListItem }, props: ["board"], data() { return { options: { group: "board", // group オプションを指定した draggable 間はDrag and Dropで要素を移すことができる animation: 100 // animationオプションを指定すると ソート時に 値(ms)で アニメーションされる } }; } }); </script>
const board = [ [ "セフィリア=アークス", "ベルゼー=ロシュフォール", "エミリオ=ロウ", "クランツ=マドゥーク" ], [ "ナイザー=ブラッカイマー", "アヌビス", "ジェノス=ハザード", "バルドリアス=S=ファンギーニ" ], [ "デイビッド=ペッパー", "リン=シャオリー", "ベルーガ=J=ハード", "メイソン=オルドロッソ" ] ];
追加可能なリスト
リストであれば、要素を追加したかったりします。
<template> <div style="margin: 50px;"> <p>追加可能なリスト</p> <draggable element="ul"> <list-item v-for="item in list" :key="list.indexOf(item)" :item="item" ></list-item> <!-- slot="footer" をつけると、リストに並ぶ異なった要素を入れることができる。 入力された値を、addItem メソッドによってリストに追加していく。 --> <div slot="footer"> <input type="text" v-model="input"/> <button @click="addItem">Add</button> </div> </draggable> </div> </template> <script> import Vue from "vue"; import ListItem from "./ListItem"; import draggable from "vuedraggable"; export default Vue.extend({ components: { draggable, ListItem }, props: ["list"], data() { return { input: "" }; }, methods: { // addItem メソッドを定義しておく addItem: function(e) { e.preventDefault(); this.list = this.list.concat(this.input); this.input = ""; } } }); </script>
ドラッグハンドルを指定したリスト
ドラッグするときのツマミを指定して、他の要素には別のイベントを仕込みたい場合などがあります。
その時は handle
オプションをつけます。
<template> <div style="margin: 50px;"> <p>ドラッグハンドルありのリスト</p> <draggable element="ul" :options="options" > <!-- list-item に dragHandle Propsを渡して、ドラッグハンドルを表示させる --> <list-item v-for="item in list" :key="list.indexOf(item)" :item="item" :dragHandle="true" ></list-item> </draggable> </div> </template> <script> import Vue from "vue"; import ListItem from "./ListItem"; import draggable from "vuedraggable"; export default Vue.extend({ components: { draggable, ListItem }, props: ["list"], data() { return { options: { // handle オプションによって、リストの中でつかめる要素を指定することができる handle: ".drag-handler" } }; } }); </script>
まとめ
Vue.Draggableを利用して、簡単にドラッグ・アンド・ドロップを実現することができました。 オプションや、ドラッグ開始時、ドロップ時の各種制御方法は以下のページに記載されているので参考にしてみてください。