借助了插件sortablejs。这种方法只适合做非树状table。如果想实现树状table,并且可拖动。可以试一下aggridVue3这个插件
<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 () {// 要拖拽元素的父容器 tbodyconst 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 () {// 要拖拽元素的父容器 头部的trconst 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的默认插槽进行实现,但是列拖动的时候,操作列的内容一直在最后一列,并没有跟着移动
代码如下,如果不需要列拖动的话,可以采取这种方式
<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 () {// 要拖拽元素的父容器 tbodyconst 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 () {// 要拖拽元素的父容器 头部的trconst 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>
还有一种解决办法就是,把操作放到弹窗操作,比如双击某一行的时候,弹出弹窗,传入这行的数据,在弹窗里面进行操作,这样就不需要添加操作内一列了。行拖动和列拖动也都能使用