こんにちは。コバヤシです。
今回はVue.jsでドラッグ&ドロップでソートする方法について書きたいと思います。
Vue.Draggableをインストールする
Vueでドラッグ&ドロップをするならこれっていうくらい定番のライブラリです。
まずこれをインストールします。
npm i -S vuedraggable
draggableを使う
draggableをコンポーネントと使用し、 ソートしたい箇所を以下のように「draggable」タグで囲みます。
<template> <div> <draggable v-model="list"> <div v-for="val in list" :key="val.id"> {{ val.name }} </div> </draggable> </div> </template> <script> const draggable = require('vuedraggable'); export default { components: { draggable: draggable }, data() { return { list: [ {id:1, name:'hoge'}, {id:2, name:'foo'}, {id:3, name:'baa'}, ] } } } </script>
これだけでソートが出来るようになります。非常に簡単ですね。
ソート開始時、ソート完了時に処理を行う
draggableタグに@startを使うことでドラッグ開始時に行う処理を指定できます。 @endで完了時です。
ソート完了時にaxiosでバックエンド側にデータを送れば、ソート順を保存できます。
<template> <div> <draggable v-model="list" @start="start" @end="end"> <div v-for="val in list" :key="val.id"> {{ val.name }} </div> </draggable> </div> </template> <script> const draggable = require('vuedraggable'); export default { components: { draggable: draggable }, data() { return { list: [ {id:1, name:'hoge'}, {id:2, name:'foo'}, {id:3, name:'baa'}, ] } }, methods: { start: () => { console.log('start') }, end: () => { console.log('end') } } } </script>
ドラッグする要素を指定する
そのままでは、draggableで囲んだ要素全体がドラッグ可能な要素となります。 handleを指定することで要素を変更することが出来ます。 下記では■の部分をクリックしたときのみドラッグが開始されます。
<template> <div> <draggable v-model="list" handle=".handle"> <div v-for="val in list" :key="val.id"> <span class="handle">■</span>{{ val.name }} </div> </draggable> </div> </template> <script> const draggable = require('vuedraggable'); export default { components: { draggable: draggable }, data() { return { list: [ {id:1, name:'hoge'}, {id:2, name:'foo'}, {id:3, name:'baa'}, ] } } } </script>
タグを変更する
デフォルトではdraggableタグはdivタグになります。
これだとtableでtrをドラッグしたい時など困ります。
そこで以下のようにタグを指定します。
<template> <div> <table> <draggable tag="tbody" v-model="list" > <tr v-for="val in list" :key="val.id"> <td>{{ val.name }}</td> </tr> </draggable> </table> </div> </template>
IE11で動かない問題
Vue.Draggableをインストールしただけでは残念ながら動きません。 以下のようなエラーが表示されます。
[Vue warn]: Error in nextTick: "TypeError: Invalid attempt to spread non-iterable instance. In order to be iterable, non-array objects must have a [Symbol.iterator]() method."
IEではSymbol.iteratorが使えないということのようです。。さすがIE。
対応するために今回はPolyfill.ioを使用することにしました。
取り敢えず、
・Array.from
・Symbol.iterator
を選択して生成されたURLを読み込んだところIE11で無事動かすことが出来ました。
<script src="https://polyfill.io/v3/polyfill.min.js?features=Symbol.iterator%2CArray.from"></script>
まとめ
Vue.Draggableを使えば簡単にソートを機能を実現できました。
設定オプションも色々あるので、様々な場面で柔軟に対応できそうです。