ドラッグ&ドロップによる要素の並び替えは、直感的でユーザーフレンドリーなUIを実現するのに効果的な手法です。
しかし、従来のドラッグ&ドロップの実装には、JavaScriptによる複雑な処理が必要でした。
htmxとSortable.jsを組み合わせることで、シンプルなHTMLの属性だけでドラッグ&ドロップによる並び替えを実現できます。
この記事では、htmxとSortable.jsを使ってドラッグ&ドロップによる要素の並び替えを実装する方法を詳しく解説します。
本記事の内容
- ドラッグ&ドロップ可能な要素のHTML構造
- Sortable.jsの設定
- 並び替え後の順序の保存
- アニメーション効果の追加
- サンプルコード
- まとめ
それでは、上記に沿って解説していきます。
ドラッグ&ドロップ可能な要素のHTML構造
htmxについてよくわからない場合は、次の記事からご覧ください。
まず、ドラッグ&ドロップ可能な要素のHTML構造を定義します。
<form class="sortable" hx-post="save_order.php" hx-trigger="end"> <div class="htmx-indicator">Updating...</div> <div><input type="hidden" name="item[]" value="1">Item 1</div> <div><input type="hidden" name="item[]" value="2">Item 2</div> <div><input type="hidden" name="item[]" value="3">Item 3</div> <div><input type="hidden" name="item[]" value="4">Item 4</div> <div><input type="hidden" name="item[]" value="5">Item 5</div> </form>
各要素には、隠し入力フィールド()を使って一意の識別子を設定します。
これにより、並び替え後の順序を保存する際に、要素を識別できるようになります。
また、要素にはhx-postとhx-triggerの属性を設定します。
hx-postには、並び替え後の順序を保存するためのサーバーサイドのエンドポイントを指定することになります。
hx-triggerには、並び替えが終了したタイミングでそのエンドポイントにリクエストを送信するように設定します。
Sortable.jsの設定
次に、Sortable.jsを使ってドラッグ&ドロップ機能を追加します。
htmx.onLoad(function(content) {
var sortables = content.querySelectorAll(".sortable");
for (var i = 0; i < sortables.length; i++) {
var sortable = sortables[i];
var sortableInstance = new Sortable(sortable, {
animation: 150,
ghostClass: 'blue-background-class',
filter: ".htmx-indicator",
onMove: function (evt) {
return evt.related.className.indexOf('htmx-indicator') === -1
},
onEnd: function (evt) {
this.option("disabled", true);
}
});
sortable.addEventListener("htmx:afterSwap", function() {
sortableInstance.option("disabled", false);
})
}
})
Sortable.jsのオプションを設定することで、アニメーション効果やゴーストエレメントのスタイル、ドラッグ不可能な要素の指定などを行います。
onMove関数では、htmx-indicatorクラスを持つ要素がドラッグされないようにしています。
onEnd関数では、並び替えが終了した後、Sortableインスタンスを一時的に無効化します。
これは、htmxによる要素の入れ替え中に予期しないドラッグイベントが発生するのを防ぐためです。
htmx:afterSwapイベントを監視し、要素の入れ替えが完了した後にSortableインスタンスを再度有効化します。
並び替え後の順序の保存
並び替え後の順序をサーバーサイドで保存するために、PHPを使います。
<?php
$items = $_POST['item'];
$jsonData = json_encode($items);
file_put_contents('order.json', $jsonData);
// ドラッグ&ドロップ後のHTML
$response = "";
foreach ($items as $item) {
$response .= '<div><input type="hidden" name="item[]" value="' . $item . '">Item ' . $item . '</div>';
}
echo $response;
?>
このPHPコードでは、POSTされた要素の識別子の配列を受け取り、JSONファイルに保存します。
また、並び替え後のHTMLを生成し、レスポンスとして返します。
htmxは、このレスポンスを受け取り、要素を入れ替えます。
アニメーション効果の追加
並び替えのアニメーションを追加することで、よりスムーズで直感的な操作感を提供できます。
.sortable {
padding: 10px;
background-color: #f0f0f0;
}
.sortable div {
padding: 10px;
margin-bottom: 5px;
background-color: white;
border: 1px solid #ccc;
cursor: move;
}
.sortable div:hover {
background-color: #f9f9f9;
}
.blue-background-class {
background-color: #e0f0ff !important;
}
これらのCSSルールにより、ドラッグ可能な要素のスタイルを設定し、ホバー時の視覚効果を追加します。
また、ゴーストエレメントの背景色を変更することで、ドラッグ中の要素の視認性を高めます。
サンプルコード
以上の内容を組み合わせた完全なサンプルコードは以下の通りです。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>htmx Sortable Example</title>
<script src="https://unpkg.com/htmx.org@1.7.0"></script>
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
<script>
htmx.onLoad(function(content) {
var sortables = content.querySelectorAll(".sortable");
for (var i = 0; i < sortables.length; i++) {
var sortable = sortables[i];
var sortableInstance = new Sortable(sortable, {
animation: 150,
ghostClass: 'blue-background-class',
filter: ".htmx-indicator",
onMove: function (evt) {
return evt.related.className.indexOf('htmx-indicator') === -1
},
onEnd: function (evt) {
this.option("disabled", true);
}
});
sortable.addEventListener("htmx:afterSwap", function() {
sortableInstance.option("disabled", false);
})
}
})
</script>
<style>
.sortable {
padding: 10px;
background-color: #f0f0f0;
}
.sortable div {
padding: 10px;
margin-bottom: 5px;
background-color: white;
border: 1px solid #ccc;
cursor: move;
}
.sortable div:hover {
background-color: #f9f9f9;
}
.blue-background-class {
background-color: #e0f0ff !important;
}
</style>
</head>
<body>
<form class="sortable" hx-post="save_order.php" hx-trigger="end">
<div class="htmx-indicator">Updating...</div>
<div><input type="hidden" name="item[]" value="1">Item 1</div>
<div><input type="hidden" name="item[]" value="2">Item 2</div>
<div><input type="hidden" name="item[]" value="3">Item 3</div>
<div><input type="hidden" name="item[]" value="4">Item 4</div>
<div><input type="hidden" name="item[]" value="5">Item 5</div>
</form>
</body>
</html>
save_order.php
<?php
$items = $_POST['item'];
$jsonData = json_encode($items);
file_put_contents('order.json', $jsonData);
// ドラッグ&ドロップ後のHTML
$response = "";
foreach ($items as $item) {
$response .= '<div><input type="hidden" name="item[]" value="' . $item . '">Item ' . $item . '</div>';
}
echo $response;
?>
このコードを実行すると、シンプルで直感的なドラッグ&ドロップによる要素の並び替えが実現されます。
なお、order.jsonには書き込み権限を付与する必要があります。
まとめ
この記事では、htmxとSortable.jsを組み合わせてドラッグ&ドロップによる要素の並び替えを実装する方法を解説しました。
htmxのhx-postとhx-trigger属性を使うことで、シンプルなHTMLだけでサーバーサイドと連携した並び替え機能を実現できます。
また、Sortable.jsを使ってドラッグ&ドロップ操作を追加し、アニメーション効果やエラーハンドリングを行うことで、ユーザーにとって使いやすく直感的なUIが作成できます。
htmxとサーバーサイドの処理を連携させることで、高速で洗練されたドラッグ&ドロップUIを実装できます。
この記事で紹介したテクニックを活用し、さらに発展させることで、ユーザーエンゲージメントを高める魅力的なドラッグ&ドロップUIを作成しましょう。


