はじめに
Vue.js と @shopify/draggable を利用して SortTable してみました。
draggable.vue
<script>
import { Sortable } from '@shopify/draggable';
const removeElement = function(node) {
return node.parentElement.removeChild(node);
};
const insertElement = function(fatherNode, node, position) {
const refNode = (position === 0) ? fatherNode.children[position] : fatherNode.children[position - 1].nextSibling;
fatherNode.insertBefore(node, refNode);
};
export default {
props: {
value: {
required: true,
type: Array,
},
element: {
required: false,
type: String,
default: 'div',
},
draggableOptions: {
required: false,
type: Object,
default: () => ({}),
},
},
mounted() {
const draggable = new Sortable(this.$el, this.draggableOptions);
this.$once('hook:beforeDestroy', () => {
draggable.destroy();
});
draggable.on('sortable:start', e => {
this.$emit('start', e);
});
draggable.on('sortable:sort', e => {
this.$emit('sort', e);
});
draggable.on('sortable:sorted', e => {
this.$emit('sorted', e);
});
draggable.on('sortable:stop', e => {
if (e.oldIndex !== e.newIndex) {
const item = removeElement(e.dragEvent.source);
insertElement(e.dragEvent.sourceContainer, item, e.oldIndex);
this.spliceList([...this.value], e.oldIndex, e.newIndex);
}
this.$emit('stop', e);
});
},
methods: {
spliceList(list, oldIndex, newIndex) {
const item = list.splice(oldIndex, 1)[0];
list.splice(newIndex, 0, item);
this.$emit('input', list);
this.$emit('change', { item, oldIndex, newIndex });
},
},
render(h) {
return h(this.element, { attrs: this.$attrs }, this.$slots.default);
},
};
</script>
app.vue
<template>
<div id="app">
<Draggable
v-model="list"
element="ul">
<li
v-for="(row, index) in list"
:key="row.id || `key${index}`"
class="draggable-source">
{{ row.text }}
</li>
</Draggable>
</div>
</template>
<script>
import Draggable from './draggable.vue'
export default {
name: 'app',
data: () => ({
list: [
{ id: 1, text: 'テスト1' },
{ id: 2, text: 'テスト2' },
{ id: 3, text: 'テスト3' },
{ id: 4, text: 'テスト4' },
{ id: 5, text: 'テスト5' },
],
}),
components: {
Draggable,
},
}
</script>
sortable:stop
イベントでソートされた DOM を元に戻し、Vue の data
自身をソートさせています。