忘れないように記録しとこ

カバの樹

Vue.jsでドラッグ&ドロップするなら「Vue.Draggable」がおすすめ

2019年5月16日

Vue.Draggableとは

Vue.Draggableは、Vue.js製のドラッグ&ドロップコンポートネントライブラリです。

現存するVue.js製のドラッグ&ドロップライブラリとしては、最大の人気を誇ります。
コンパイルを必要としないUMD用のJSファイルが用意されているので、jQueryからの切り替えも容易に行う事が可能です。
単純にドラッグ&ドロップの機能が欲しければ、このライブラリを選んでおけば問題無いはずです。

主な使用用途並び順を変更するのはもちろん、複数のエリアを移動することが可能です。
さらにスマホにも対応しており、タッチイベントによる移動も可能となっています。

 

【動画サイズ:87KB】

 

環境

この記事は、以下の管理人の検証環境にて記事にしています。

vue.js 2.5.8
Vue.Draggable 2.24.3

 

Vue3対応

Vue3を使用する場合は下記のURL
https://www.kabanoki.net/9532/

 

ライブラリの取得

ライブラリを取得するには、npm, yarn, CDNのどれか一つを使用します。

npm

npm i -S vuedraggable 

yarn

yarn add vuedraggable

CDN

<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.8.4/Sortable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.23.2/vuedraggable.umd.min.js"></script>

 

直接「Vue.Draggable」のリポジトリを取得する場合は、以下のURLから取得できます。

https://github.com/SortableJS/Vue.Draggable

 

導入手順

管理人が行った、動作確認サンプルを実装するために、以下の手順でソースコードを導入していきます。
このサンプルは、1つのエリアの中で並び順を変更するものになります。

 

1. ライブラリの呼び出し

まずライブラリを呼び出す為に、以下の2通りのケースで呼び出します。

ES6等で実装する場合

import draggable from 'vuedraggable' 

CDNで実装する場合

const draggable = window['vuedraggable'];

 

2.テンプレートを準備

<draggable> の内部がドラッグ可能なエリアになります。
tagプロパティへuldivのような外部要素タグを設定します。

<draggable> で囲まれた内部にドラッグするリスト要素を設置します。
サンプルでは、v-forを使ってループでリストを設定しています。

ポイント

ループに使う配列は、data から直接渡しても良いですし、computed を使っても大丈夫です。

<div id="app">
  <draggable tag="ul">
    <li v-for="item, index in items" :key="item.no">{{item.name}}-(No.{{item.no}})</li>
  </draggable>
</div>

注意ポイント

リストのkeyプロパティを忘れずに設定しましょう!
これが無いと要素の追加・削除で、バグが多発するので必ず設定しましょう!

 

3.JavaScriptを設定

1で取得したdraggablecomponents プロパティに設定します。

今回のサンプルはdateから直接ループに値を渡します。
リスト用の配列データitemsを設定します。

new Vue({
  el: "#app",
  components: {
    'draggable': draggable,
  },
  data: {
    items:[
      {no:1, name:'キャベツ', categoryNo:'1'},
      {no:2, name:'ステーキ', categoryNo:'2'},
      {no:3, name:'リンゴ', categoryNo:'3'}
    ]
  }
});

 

4. リストにスタイルを適用する

Vue.DraggableにはjQuery uiのような専用のスタイルが無いので、見た目を整えるためにスタイルを自作する必要があります。

今回はサンプル用に下記のようなスタイルを適用します。

ul {
  list-style-type: none;
}
li {
  cursor: pointer;
  padding: 10px;
  border: solid #ddd 1px;
}

 

サンプル

今回のソースを実際に触って確認できるようにデモを用意しました。

>>専用ページで確認する

 

 

複数エリアの導入手順

次に上の1つのエリア内で並び順を変更するサンプルを参考にして、二つのエリアをドラッグ移動できるサンプルを実装するための導入を行ってみます。
以下の手順にしたがって、実装を行っていきます。

 

1.テンプレートを準備

ドラッグ移動が可能なエリアを用意する為に、<draggable>を2つ準備します。

2つの<draggable>エリアにoptions{group:'ITEMS'}を持たせます。
これで2つ<draggable>エリアを自由に行き来させることができます。

<div id="app">
  <div id="box1" class="box">
    <draggable tag="ul" :options="{group:'ITEMS'}">
      <li v-for="item, index in items" :key="item.no">{{item.name}}-(No.{{item.no}})</li>
    </draggable>
  </div>
  <div id="box2" class="box">
    <draggable tag="ul" :options="{group:'ITEMS'}">
      <li v-for="item, index in items2" :key="item.no">{{item.name}}-(No.{{item.no}})</li>
    </draggable>
  </div>
</div>

注意ポイント

エリア内のリストが空になると再ドラッグがし辛くなります。
<draggable> に、スタイルでpadding:3pxみたいに厚みを持たせてあげるとドラッグがし易くなります

 

2. 複数のdraggableリスト用に配列を用意する

2つのドラッグエリア用のリストをdataに用意します。

new Vue({ 
  el: "#app",
 components: {
   'draggable': draggable,
  },
  data: { 
    items:[ 
      {no:1, name:'キャベツ', categoryNo:'1'}, 
      {no:2, name:'ステーキ', categoryNo:'2'} 
    ], 
    items2:[ 
      {no:5, name:'きゅうり', categoryNo:'1'},
      {no:6, name:'ハンバーグ', categoryNo:'2'} 
    ] 
  }
});
 

 

サンプル

今回のソースを実際に触って確認できるようにデモを用意しました。

>>専用ページで確認する

 

 

イベント

ドラッグイベントは、任意のタイミングで動作します。
9種類のタイミングが用意されています。

 

イベント一覧

イベント タイミング
start ドラッグ開始したとき
add 要素が追加されたとき
remove 要素を削除されたとき
update ドラッグで要素の移動が完了したとき
end ドラッグが完了したときの最後に動作します
choose ドラッグ要素を選択したとき
sort 並び順を変更したときのupdateの後、endの前に動作する
filter フィルターされたとき
clone ドラッグ時のシャドークローンが生成されたとき

 

イベント導入例

今回はendイベントを例に使って解説します。

step.1 onEnd関数を作成する

まずイベントを作成します。
onEndというイベントをmethodsに作成します。
onEndの第一引数を設定しておくと、ドラッグアイテムのイベント情報が格納されます。
これで、ドラッグ後にイベントを反応させられます。

methods: {
  onEnd: function(originalEvent){
    console.log(originalEvent);//originalEventは イベントを取得できる
  }
}

 

step.2 @end="onEnd"をコンポーネントに設定する

上記で作成したonEndイベントを<draggable>に設定します。

<ul>
 <draggable @end="onEnd">
   <li v-for="item, index in items" :key="item.no">{{item.name}}-(No.{{item.no}})</li>
 </draggable>
</ul>

 

リストに新規で追加する方法

あらかじめ用意されたリストに新規でドラッグ要素を追加したい場合は、以下が参考になります。

 

スクリプト

リストの配列にarray.pushを使って、新規のアイテムを追加します。
今回はdoAddというmedhodsを作成して、items配列にpush()でオブジェクトを追加していきます。

 
new Vue({
  el: "#app",
  data: {
    items:[
      {no:1, name:'キャベツ', categoryNo:'1'},
      {no:2, name:'ステーキ', categoryNo:'2'},
      {no:3, name:'リンゴ', categoryNo:'3'}
    ],
    newNo: 4
  },
  computed: {
    myList: function(){
      return this.items;
    }
  },
  methods: {
    doAdd:function(){
      var self = this;
      var no = 0;
      // itemsの中の一番大きなnoを取得して1を足す
      if(self.items.concat().length > 0){
        no =  Math.max.apply(null,self.items.concat().map(function(item){return item.no;})) +1;
        self.newNo = self.newNo < no ? no:self.newNo;
      }
    // itemsにアイテムを追加
      this.items.push(
        {
          no: this.newNo,
          name:'追加リスト'+ this.newNo,
          categoryNo:'5'
        }
      );
    },
  }
});

 

HTML

ボタンを用意して、クリックするとdoAddイベントが起動します。

<ul id="app">
 <button v-on:click="doAdd">追加</button>
 <draggable>
   <li v-for="item, index in myList" :key="item.no">{{item.name}}-(No.{{item.no}})</li>
 </draggable>
</ul>

 

サンプル

>>専用ページで確認する

 

リストから削除する方法

リストの中からドラッグ要素を削除したい場合は、以下が参考になります。

 

スクリプト

リストの配列からarray.spliceを使って、アイテムを削除します。
doDeleteというmedhodsを作って、引数で配列のindexを受け取って、splice(index, 1)で削除します。

 
new Vue({
  el: "#app",
  data: {
    items:[
      {no:1, name:'キャベツ', categoryNo:'1'},
      {no:2, name:'ステーキ', categoryNo:'2'},
      {no:3, name:'リンゴ', categoryNo:'3'}
    ]
  },
  computed: {
    myList: function(){
      return this.items;
    }
  },
  methods: {
    doDelete: function(index){
      this.items.splice(index, 1);
    },
  }
});

 

HTML

削除ボタンをクリックしてdoDeleteイベントを起動します。
引数にindexを持たせます。

<ul id="app">
 <draggable>
   <li v-for="item, index in myList" :key="item.no">
   {{item.name}}-(No.{{item.no}})
   <span class="del" v-on:click="doDelete(index)">[削除]</span>
   </li>
 </draggable>
</ul>

 

サンプル

>>専用ページで確認する

 

ドラッグ時の掴める箇所やアニメーションを設定

Vue.Draggableは、Sortable.jsを元にしているので、同ライブラリのオプションを利用することができます。
例えば以下のようなオプションをしようすることができます。

カスタマイズできるモノ

  • ドラッグアイテムの掴める箇所を指定する(ハンドラーを設定)
  • ドラッグアイテムの移動時にアニメーションを設定する
  • ドラッグ可能にするまでに時間を設定する

 

Sortable.jsのオプションを実装してみたい方は、以下の記事が参考になります。

参考
Vue.DraggableでSortable.jsのオプションを使う

この記事は、「Vue.Draggable」でSortable.jsのオプションを使う方法を書いています。

続きを見る

 

リストの並び順をブラウザに保存する

WEBアプリなどでブラウザに並び順を保存したい時などは、下記の記事が参考になります。

参考
「Vue.Draggable」の並び順をブラウザに保存する方法

以前から「Vue.Draggable」の並び順をブラウザに保存したいなあと思っていました。先日「vue-ls」というブラザストレージを操作するライブラリの記事を書いた際に、勢いで「Vue.Draggable」と組み合わせたシステムを作成しました。

続きを見る

 

ドラッグリストをフィルタリングする

特定の文字を含むリストを並べ替えたり、カテゴリー絞り込みをしたい時の参考記事を書きました!↓

参考
Vue.Draggableでフィルタリングされたリストを使用する

Vue.Draggableを使いながらリストをフィルタする機能が欲しいと思いました。
しかし、Vue.Draggableの特性と言いますか、制限のようなものでcomputedが使用できません。
そこで別のやり方で実装しました。

続きを見る

 

テーブルの列を並び替える

テーブルの列の順番を並び替える方法を記事にしました。
下記の記事を参考にしてください。

参考
Vue.jsでテーブルの列移動を実装する

いつもの如くクライアントからデータ用テーブルの列を並び替えしたいとの要望がありました。
遥か昔の記憶で、Vue.Draggableを使ってサンプルを作った記憶があったので、引っ張り出してみました。

せっかくなので、記事にしようと思います。

続きを見る

 

さいごに

Vue.js製のドラッグ&ドロップコンポートネントライブラリでした。

管理人が実務で触った感触的には、ドラッグ&ドロップするならこのライブラリを選んでおけば問題ないと思います。
よっぽど特殊なことをやりたいなら、このライブラリをカスタマイズするよりも別のライブラリを使うのが無難だと思います。

そういう意味では、Vue.js製のドラッグ&ドロップ系ライブラリは結構種類が豊富です。

今後そういったライブラリをご紹介していければと思います。

 

おまけ

別のライブラリになってしまいますが、ツリー形式にドラッグ要素を配置できるものもあります。
これを使えばWordpressのメニュー的なのも作れそうですね。

参考
「vue-draggable-nested-tree」でドラッグ要素をツリー形式で配置する

vue-draggable-nested-treeは、ドラッグ要素をツリー形式に配置することが可能なdraggable&droppableコンポーネントです。tree-helper.js を使用することで、折りたたみを実装することも可能です。簡単に実装できるコピペと触って体感できるサンプルを掲載しています。

続きを見る

 

今日はこの辺でー

 

  • B!