Svelteで簡単にできるテーブル行の並び替え(ドラッグ&ドロップ)

ライブラリを利用することなく短時間でシンプルなコードを利用してドラッグ&ドロップでテーブル行の並び替えをしたいと思ったことはないですか?本文書ではSvelte環境でドラッグ&ドロップを利用してテーブル行の並び替えを行う方法を説明しています。実装にはdragstart, dragend, dragover, dragenterイベントを利用しているのでSvelteでのdragイベントに馴染みがない人のdragイベントの学習にも利用することができます。
動作確認はmacOSを利用、Svelteのバージョンは3.52です。
目次
プロジェクトの作成
npm create vite@latestコマンドを利用してSvelteプロジェクトを作成します。templateにはsvelteを指定します。プロジェクトの名前は任意の名前をつけることができます。ここではsvelte-table-row-reorderという名前をつけています。
プロジェクトの作成後は作成されたフォルダsvelte-table-row-reorderに移動します。
UserTable.svelteファイルのの作成
srcフォルダに存在するlibフォルダの下にUserTable.svelteファイルを作成します。作成後以下のコードを記述します。
srcフォルダのApp.svelteファイルを開いて作成したUserTableコンポーネントをimportします。
npm run devコマンドで開発サーバを起動してUserTableコンポーネントの内容が表示されるか確認します。

データの取得
並び替えに利用するデータは無料で利用できるJSONPlaceHolderを利用します。https://jsonplaceholder.typicode.com/usersにアクセスすると10名分のユーザ情報を取得することができます。どのようなデータが取得できるかはブラウザからでも確認できます。
取得したデータを保存するためにローカル変数のusersを定義します。
データの取得はコンポーネントがマウント直後に実行されるonMount関数の中で実行します。fetch関数で取得したデータを定義したusers変数に保存します。users変数に保存された内容を表示するためにeach…ブロックによる配列の展開を行なっています。eachブロックに含まれている配列の要素番号であるindexは後ほど利用します。
ブラウザで確認すると10名分のユーザ情報が一覧で表示されます。

テーブルには罫線が表示されていないのでstyleタグを追加して設定を行います。
UserTable.sveluteファイルに以下を追加します。
styleタグをUserTable.svelteファイルに追加後再度ブラウザを確認するとテーブルには罫線がついて表示されます。

テーブル行の並び替えを実装するための準備は完了です。
並び替え処理
draggableの設定
現在の設定では行の要素をマウスで掴みドラッグを行うことはできません。要素をドラッグできるようにするためにはdraggable属性を設定する必要があります。tr要素にdraggable属性を設定します。
設定後は移動した要素の上にマウスを移動して左ボタンで要素を掴むことができるようになります。ボタンを押している間要素をドラッグすることができます。下記の図はIDを10を持つtr要素をドラッグしています。

ドラッグした要素上で押していたボタンを外すとその場所に要素が追加できるように設定を行なっていきます。
dragstartイベントの設定
要素を掴んでドラッグを開始した直後に発火するdragstartイベントの設定を行います。dragstartイベントがドラッグ直後に発火するのかどうか確認を行います。dragstartイベントはon:dragstartで取得することができイベントが発火したらdragStart関数を実行します。
設定したdragStart関数を定義します。
要素をドラッグしてブラウザのデベロッパーツールのコンソールに”drag start”が表示されることを確認してください。
確認できたら次はdragstartイベントでドラッグした要素のindex(配列の要素番号)を保存します。indexを保存するためにdragIndexを定義します。初期値をnullに設定しています。
dragstartイベントが発火した際にindexの情報を取得するためにdragStart関数の引数にindexを指定します。
dragStart関数では引数で取得したindexを受け取ることができるので受け取ったindexにdragIndexに保存します。
設定後、要素をドラッグすると”drag start”の文字列の横にドラッグした要素のindexが表示されることを確認してください。indexは配列の要素番号なのでドラッグした要素によって0から9の値が表示されます。
dragstartイベントの設定は完了したのでconsole.logの行は削除しておきます。
dragenterイベントの設定
ドラッグした要素が別の要素に入った時に発火するdragenterイベントをtr要素に設定します。dragenterイベントが発火されるとdragEnter関数が実行され引数にはindexを指定しています。indexにはドラッグした要素が入ってきた要素のindexが入ります。ドラッグしている要素のindexではありません。
dragEnter関数でドラッグした要素のindexが保存されているdragIndexとドラッグした要素が入ってきた要素のindexを確認します。
同じ要素をドラッグしている間はdragIndexは同じ値が表示され、tr要素を超えていく度に異なるindexがコンソールに表示されることを確認してください。
確認ができたら、indexとdragIndexの値が異なる場合のみ要素の入れ替えを行う処理を追加します。
JSON.parse(JSON.stringify(users))でusersの配列のコピーをnewUsers変数に保存します。spliceメソッドとdragIndexを利用してドラッグした要素をnewUsersの配列から削除しています。削除した要素(ドラッグした要素)がspliceメソッドの戻り値の配列番号の0に入っているのでdeleteElementに保存しています。再度spliceメソッドを実行して今度はindexの場所に削除した要素を追加しています。これで入れ替え処理を行うことができます。
spliceメソッドの処理の詳しい内容についてはMDNなどで確認してください。
配列を入れ替えた後はdragIndexにドラッグした要素が入れ替わった後のindexを設定しています。
これで並び替えの処理は完了です。一番上のIDが1の要素をドラッグして一番下の要素に移動できるか確認してください。

dragoverイベント
OSやブラウザによってドラッグで要素を移動した後にドロップする(並び替えは完了)と半透明の要素が元の場所に戻るような動作をします。その動作を止めるためにdragoverイベントを設定します。dragoverイベントではデフォルトの処理を停止するためpreventDefaultを実行します。dragoverイベントでpreventDefaultを実行するとドラッグした要素をドロップしても半透明の要素が元の場所に戻るという動作がなくなります。
dragendイベント
ここではJSONPlaceHolderを利用しているのでデータの取得を行うことはできますがデータの保存を行うことができません。実際のアプリケーションでは並び替えを行なった後のデータを保存する処理が必要になります。データ保存の処理を行う場所としてdragendイベントを利用します。
dragendイベントはドロップした際に発火されます。
dragEnd関数を追加し、ドラッグを止めた(ドロップ)時にイベントが発火するか確認します。
ドラッグのために押していたボタンを離した時にコンソールに”drop”が表示されることを確認してください。
並び替え後のデータをサーバに送信する等の処理をdragEnd関数の中に記述します。dragEndが実行される時は並び替えの処理が完了しているのでdragIndexの値を初期値のnullに戻しておきます。
ドラッグ要素を目立たせる
ドラッグした要素を目立たせるためにドラッグ要素にスタイルを設定します。
indexとdragIndexの値が等しい時にclassのdraggingを適用します。
draggingクラスはscriptタグに追加します。
ドラッグしている要素にスタイルを適用することでドラッグしている要素が先ほどよりもわかりやすくなりました。

作成したUserTable.svelteファイルは下記の通りです。