ドラッグアンドドロップできるファイルソートUIを作った

f:id:kawauso7c:20170816192849g:plain

検証サイト: https://kawausokun.github.io/reordering/
ソース: GitHub - kawausokun/reordering: Reordering UI (experimental)

ファイル・フォルダをソートできるようなUIが必要になった。
単一のリストでのソートなら特に面倒なことはないが、フォルダを考慮する必要があると難易度が上がる。操作者が並び替えたいのかフォルダに突っ込みたいのかを判定しないといけない。
Fancytree - Example Browser のUIを参考にした。

基本的な考え方

一般的なドラッグアンドドロップによるソートUIは、ドラッグ中に即時ソートするものも多い。(例: Vue.jsのリストレンダリングとhtml5のドラッグ&ドロップの実装 - Qiita)
しかしファイルをフォルダに入れる時などは、ドロップ先が移動したり変化したりすると、狙ったところに移動させにくくなる。なので、Fancytreeのように, ドラッグ中は挿入先を示すマークを表示し、ドラッグ終了時にファイルを移動させる方が良い。

f:id:kawauso7c:20170816194847p:plain

挿入場所は以下のように分類できる。

  • ドロップ先ファイル・フォルダの直前に挿入
  • ドロップ先ファイル・フォルダの直後に挿入
  • ドロップ先フォルダに挿入

ドロップ先がフォルダの時、前後に挿入したいのかフォルダに入れたいのかを判定する必要がある。ドロップ先の要素内での、カーソルの座標で決定することにする。

f:id:kawauso7c:20170816201608p:plain

ドロップ先要素の上部にカーソルがある場合は「直前に挿入」、下部なら「直後に挿入」、真ん中なら「フォルダに挿入」とみなす。
ドロップ先がファイルなら「直前に挿入」と「直後に挿入」だけ。

検証サイトでドラッグ中に表示される"y"はドロップ先要素内でのカーソルのY座標、"mode"は挿入場所を示している。

実装

Vue.jsで実装している。
Y座標さえ計算できれば、挿入場所を判定し、ドロップ先要素にクラスを付与することで、挿入先を示すマークをCSSで表現できる。

注意

  • 現状フォルダの中にフォルダは挿入しない想定。やるとしたらファイル・フォルダをコンポーネント化し再帰する実装とするだろう。
  • 製品とするならもう一歩使い勝手向上を狙いたい。例えばファイルが入ったフォルダがリストの最後にある場合に、そのフォルダの下に挿入できない。