借助了插件sortablejs。这种方法只适合做非树状table。如果想实现树状table,并且可拖动。可以试一下aggridVue3这个插件
javascript
<template>
<div class="draggable" style="padding: 20px">
<el-table row-key="id" :data="tableData" style="width: 100%">
<el-table-column v-for="(item, index) in oldList" :key="`col_${index}`" :prop="newList[index].prop"
:label="item.label" align="center">
</el-table-column>
</el-table>
</div>
</template>
<script setup lang="ts">
import Sortable from 'sortablejs'
import { onMounted, ref } from 'vue'
// 只适合做平级的table行和列拖动
const oldList = ref()
const newList = ref()
// 表头
const tableItems = ref([
{
label: '姓名',
prop: 'name',
},
{
label: '性别',
prop: 'gender',
},
{
label: '年龄',
prop: 'age',
},
])
// 表体数据
const tableData = ref(
[
{
id: 1,
name: '李四',
gender: '男',
age: 20,
},
{
id: 2,
name: '王五',
gender: '未知',
age: 18,
},
{
id: 3,
name: '张三',
gender: '男',
age: 22,
},
]
)
// 行拖拽
const rowDrop = function () {
// 要拖拽元素的父容器 tbody
const tbody = document.querySelector('.draggable .el-table__body-wrapper tbody')
Sortable.create(tbody, {
// 可被拖拽的子元素
draggable: ".draggable .el-table__row",
onEnd({ newIndex, oldIndex }) {
// newIndex 拖动到的新的索引
// oldIndex 没拖动前的索引
const currRow = tableData.value.splice(oldIndex, 1)[0]
tableData.value.splice(newIndex, 0, currRow)
}
});
}
// 列拖拽
const columnDrop = function () {
// 要拖拽元素的父容器 头部的tr
const wrapperTr = document.querySelector('.draggable .el-table__header-wrapper tr');
Sortable.create(wrapperTr, {
animation: 180,
delay: 0,
onEnd: (evt: any) => {
const oldItem = newList.value[evt.oldIndex];
newList.value.splice(evt.oldIndex, 1);
newList.value.splice(evt.newIndex, 0, oldItem);
}
})
}
onMounted(() => {
oldList.value = JSON.parse(JSON.stringify(tableItems.value))
newList.value = JSON.parse(JSON.stringify(tableItems.value))
columnDrop()
rowDrop()
})
</script>
效果如下
我试了加操作列,通过el-table-column的默认插槽进行实现,但是列拖动的时候,操作列的内容一直在最后一列,并没有跟着移动
代码如下,如果不需要列拖动的话,可以采取这种方式
javascript
<template>
<div class="draggable" style="padding: 20px">
<el-table row-key="id" :data="tableData" style="width: 100%">
<el-table-column v-for="(item, index) in oldList" :key="`col_${index}`"
:label="item.label" align="center">
<template #default="{ row, column, $index }">
<div v-if="column.label !== '操作'">
{{ row[newList[index].prop] }}
</div>
<div v-else>
<el-button size="small">操作</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup lang="ts">
import Sortable from 'sortablejs'
import { onMounted, ref } from 'vue'
// 只适合做平级的table行和列拖动
const oldList = ref()
const newList = ref()
// 表头
const tableItems = ref([
{
label: '姓名',
prop: 'name',
},
{
label: '性别',
prop: 'gender',
},
{
label: '年龄',
prop: 'age',
},
{
label: '操作',
prop: 'operate',
},
])
// 表体数据
const tableData = ref(
[
{
id: 1,
name: '李四',
gender: '男',
age: 20,
},
{
id: 2,
name: '王五',
gender: '未知',
age: 18,
},
{
id: 3,
name: '张三',
gender: '男',
age: 22,
},
]
)
// 行拖拽
const rowDrop = function () {
// 要拖拽元素的父容器 tbody
const tbody = document.querySelector('.draggable .el-table__body-wrapper tbody')
Sortable.create(tbody, {
// 可被拖拽的子元素
draggable: ".draggable .el-table__row",
onEnd({ newIndex, oldIndex }) {
// newIndex 拖动到的新的索引
// oldIndex 没拖动前的索引
const currRow = tableData.value.splice(oldIndex, 1)[0]
tableData.value.splice(newIndex, 0, currRow)
}
});
}
// 列拖拽
const columnDrop = function () {
// 要拖拽元素的父容器 头部的tr
const wrapperTr = document.querySelector('.draggable .el-table__header-wrapper tr');
Sortable.create(wrapperTr, {
animation: 180,
delay: 0,
onEnd: (evt: any) => {
const oldItem = newList.value[evt.oldIndex];
newList.value.splice(evt.oldIndex, 1);
newList.value.splice(evt.newIndex, 0, oldItem);
}
})
}
onMounted(() => {
oldList.value = JSON.parse(JSON.stringify(tableItems.value))
newList.value = JSON.parse(JSON.stringify(tableItems.value))
columnDrop()
rowDrop()
})
</script>
还有一种解决办法就是,把操作放到弹窗操作,比如双击某一行的时候,弹出弹窗,传入这行的数据,在弹窗里面进行操作,这样就不需要添加操作内一列了。行拖动和列拖动也都能使用