記事を書こうと思ったキッカケ
業務の中で、Vueで並び替えた要素をバックエンド側にソート順も含めて送信し保存する実装を行ったのですが、なかなかに苦戦してしまったので備忘録をと思いまして・・・
動作イメージ
親の中に子要素があり、子要素の順番は子要素間で入れ替えが行えて親要素は親要素間で入れ替えができるような動きを作りたかった(語彙力)
使用したライブラリ
VueDraggable
https://github.com/SortableJS/Vue.Draggable
実装したコードの一例
<script setup>
const props = defineProps({
draggable: {
type: Object
},
})
// 親要素を追加する関数
const addParent = () => {
const newSort = form.draggable.length ? Math.max(...form.draggable.map(el => el.id)) + 1 : 1;
const newId = form.draggable.length ? Math.max(...form.draggable.map(el => el.id)) + 1 : 1;
form.draggable.push({
id: newId,
sort: newSort,
title: '',
items: []
});
};
// 子要素を追加する関数
const addChild = (parentId) => {
const parent = form.draggable.find(p => p.id === parentId);
if (parent) {
const newId = parent.items.length ? Math.max(...parent.items.map(el => el.id)) + 1 : 1;
const newSort = parent.items.length ? Math.max(...parent.items.map(el => el.sort)) + 1 : 1;
parent.items.push({
id: newId,
sort: newSort,
title: '',
});
}
};
// 親要素を削除する関数
const deleteParent = (parentId) => {
...
};
// 子要素を削除する関数
const deleteChild = (parentId, childId) => {
...
};
// 親の順番を入れ替えたときに情報を更新する関数
const atEndParent = () => {
...
};
// 子の順番を入れ替えたときに情報を更新する関数
const atEndChild = (parentId) => {
...
};
// 保存
const submit = () => {
...
}
</script>
<template>
<draggable v-model="form.menu" group="parents" item-key="id" @end="atEndParent">
<template #item="{ element: parent }">
<div class="parent">
...親要素の削除ボタンとか子要素追加ボタンとか入れる
</div>
<draggable v-model="parent.items" group="children" item-key="id" @end="atEndChild(parent.id)">
<template #item="{ element }">
<div class="childlen">
...子要素に詰め込みたいものを入れる
</div>
</template >
</draggable>
</template >
</draggable>
</template>
引っかかったポイント①
単純に動かなかった。
vue3からは#item="{ element }
↑この記載が必須になり、記載がないとエラーになります。
完全にvue2の情報を見ており、初歩的なミス過ぎて書くかどうかも迷いました()
引っかかったポイント②
要素を入れ替えて表示上は入れ替わっているが、sortの値が変動しない
ソート順を保存するためにsortの値を保持させるために@endイベントで並び替えが終わったときに並び順を更新する処理を入れていなかったためでした・・・
※ @endはドラッグアンドドロップが終わった際に着火するイベントになります。
他にもvuedraggableにはstart, add, removeなど便利なイベントトリガーがあるので気になる方は調べてみてください
引っかかったポイント③
親要素は親要素同士、子要素は子要素同士で入れ替えをしたかったのにうまくいかない。
今回、親は親同士、子は子同士でのみ入れ替えをしたかったのですが、どうやらgroupで指定していないといけなかったようでgroupを指定してあげるとgroupで指定した値が合致したコンポーネント間でしか移動ができないように制限ができます。
→ group="parent"とgroup="children"はこれで行き来できないですね
さいごに
自分自身がサーバーサイドをメインに実装しておりフロントをあまり触らないこともあり(言い訳)
こんな便利なライブラリを用意してくれている世の有識者に対して足を向けて眠れないような恥ずかしい箇所で躓いてしまいましたが、個人的にはいい勉強になったかなと思います。
フロントエンドの領域も奥が深く、サーバーサイドにはない面白さを感じられたので、今後も積極的に学習を進めていこうと思いました。