Vue.js2系でorderByを使ってドラッグアンドドロップでDOMの並び順を変える

2017-10-01 2017-12-26

とあるプロジェクトで、「なんか流行ってるしVue.js使ってみよう」ということで、色々いじっていた時の副産物です。

Vue.jsは2系とそれ以前で仕様がかなり異なるため、1系で使えていたorderByなどのbuilt-inフィルタが使えなくなっており、computed(算出プロパティ)で使うしかなくなっています。

多分上述した理由で苦戦している人もいるかと思うので、メモ代わりに置いておきます。

学習コストが低いことがVue.jsの売りの一つだったと思いますが、そうでもないんじゃないかと思い始めています。

orderByを使うための前準備説明

公式サイトで「orderBy」と入れて検索するとここにたどり着くと思います。

要約すると「2系はcomputedで使えるよ!」とのことです。

ですが、いきなり「_.orderBy」と言われてもこちらも困ります。それvue.jsじゃなくね?

そうです。このアンダースコアから始まる関数は、Lodashというライブラリの関数です。こいつを読み込んであげないと、下記のjsは動きません。

ということでまずはhtmlから。

html

Vue.js的に注目すべきポイントはorderedItemsです。dataに設定しているitemsではなく、orderedItemsをv-forで利用していることに注目してください。

draggableとかはhtml5の領域なので、ここでの説明は省きます。

js

vue.js的なポイントとしてはcomputedですが、ここは公式サイトに書いてある通りなので大丈夫でしょう。loadshのorderByを利用して、DOM要素の並び替えを行っています。

どちらかというと、dragenterの挙動で苦しむ人が多いんじゃないかと思います。dragenterはドラッグ中の要素が、ドロップ領域に入ったタイミングで発火するため、各DOM要素の上を通過したタイミングでorderが入れ替わることになります。

この例でいうと、「こんにちわ」をドラッグしたまま下にマウスカーソルをずらしていくと、「おはようございます」の要素に重なった瞬間に「こんにちわ」と「おはようございます」の位置が入れ替わり、「いただきます」を通過した後にドロップすることで、「おはようございます」「いただきます」「こんにちわ」の順に並ぶことになります。

こんにちわ
おはようございます
いただきます

おはようございます
いただきます
こんにちわ

という感じです。

なお、このサンプルソースはドラッグ中にドロップ領域に重なったタイミングでorderが変わる仕組みとなっているため、ドラッグ中に他のDOM要素を避けるようにしてマウスカーソルを動かした場合、ドロップ領域として指定したDOM要素と位置が入れ替わることになります。

上記の例でいうと、「こんにちわ」をドラッグしたまま、「おはようございます」の要素を回避して、そのまま「いただきます」を通過した後にドロップした場合、「いただきます」「おはようございます」「こんにちわ」の順に並ぶということです。

これを避けたいのであれば、orderを振りなおすような仕組みが必要になります。