この記事は vue.js v1.x でのみ動作確認済みです。
v2.x では orderBy など動作しない記述がございますので、ご注意ください。
公式サイトではmousedownやtouchstartなどのイベントをトリガーに実装したサンプルがあります。これをうまく使えばドラッグ&ドロップの実装もできそうですが、今回はhtml5のdraggableを使用してみました。
@mousedown="startDrag"
@touchstart="startDrag"
@mousemove="onDrag"
@touchmove="onDrag"
@mouseup="stopDrag"
@touchend="stopDrag"
@mouseleave="stopDrag"
デモと実際のコードはこちら
解説
HTML5からdraggable="true"
とすることで、ドラッグ可能な要素にすることができます。
こちらの記事を参考に勉強しました。
ネイティブ HTML5 ドラッグ&ドロップ
<ul class="dropArea">
<li class="draggable" v-for="item in items | orderBy 'index'"
draggable="true"
@dragstart="dragstart(item, $event)"
@dragend="dragend"
@dragenter="dragenter(item)"
>{{item.text}}</li>
</ul>
cssはお好みで適当に。
.dropArea {
padding: 0;
margin: 0;
}
.dropArea .draggable {
list-style: none;
margin: 10px;
padding: 0;
width: 100px;
height: 40px;
background-color: #3498db;
}
ドラッグした要素を記憶しておき、dragenter
をトリガーに、items
のindex
を入れ替えます。index
をkey
として、表示はhtmlのほうでv-for="item in items | orderBy 'index'"
という形で自動ソートさせています。
var app = new Vue({
el: 'body',
data: {
draggingItem: undefined,
items: [{
text: "A",
index: 0
},{
text: "B",
index: 1
},{
text: "C",
index: 3
},{
text: "D",
index: 2
}]
},
methods: {
dragstart (item,e) {
this.draggingItem = item
e.target.style.opacity = 0.5;
},
dragend (e) {
e.target.style.opacity = 1;
},
dragenter (item) {
const tempIndex = item.index;
item.index = this.draggingItem.index
this.draggingItem.index = tempIndex
}
}
})
入れ替え動作に対して、アニメーションを実装しようと思ったのですが、position: absolute
やfixed
を使用した形でしか思いつかなかったので、やめました。
Vue.jsでバインディング可能なイベント一覧です。
@click
@submit
@keyup
@mousedown
@mousemove
@mouseup
@mouseleave
@touchstart
@touchmove
@touchend
@dragstart
@dragenter
@dragleave
@dragover
@dragend
これって、公式サイト(events)に整理された情報がないのですが、DOMのイベント(MDN参照)が色々と使えるという認識であっていますでしょうか?お詳しい方いらっしゃれば是非コメントお願いします!
以上です。
配列のデータは簡単に追加や削除の機能を実装することもできるので、用途に応じて拡張が可能かと思います。他にも「Vue.jsとドラッグ&ドロップ」をテーマにした似た形のコードがありましたが、Vue.jsのバージョンが古かったり、やっぱり自分で書いてみたかったりしたので。
今回のタイトルとは関係ありませんが、Vue.jsの勉強情報
Vue.jsもReactのようにソースが溢れていれば良いのになと日々感じておりますが、個人的にはVueStrapのコードの書き方が最近では、一番勉強になりました。これをBootstrapのように使えるかというと、正直物足りなさすぎますが、コードが気軽に読めるのでありがたかったです。