element+Sortable 实现表格拖拽

<template>
    <div :class="props.className" style="padding: 8px 0;">
        <el-table :ref="props.refsName" row-key="id" :data="state.tableData" style="width: 100%" highlight-current-row
            @current-change="handleCurrentClick">
            <el-table-column label="序号" prop="serialNumber" width="65" align="center" />
            <el-table-column type="expand" width="50" align="center">
                <template #default="scope">
            // 组件调用自己 <drag-table style="margin-left: 20px;" :className='className + "-" + scope.row.id' :tableData="scope.row.children" :tableConfig="state.tableConfig" v-if="scope.row.children && scope.row.children.length" @childrenChange="childrenClick" :refsName="props.refsName + scope.row.id" :rowId="props.rowId" /> </template> </el-table-column> <el-table-column v-for="(item, index) in state.oldList" :key="`col_${index}`" :prop="state.newList[index].prop" :label="item.label" align="center" /> <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width"> <template #default="scope"> <el-button type="text" icon="Connection" @click="toDetail(scope.row)">编辑</el-button> <el-button type="text" icon="Delete" @click="delById(scope.row)">删除</el-button> </template> </el-table-column> </el-table> </div> </template> <script setup name="DragTable"> import Sortable from 'sortablejs'; import { reactive, onMounted, watch, ref } from 'vue'; const { proxy } = getCurrentInstance(); const props = defineProps(['className', 'tableData', 'tableConfig', 'refsName', 'rowId']) const emit = defineEmits(['childrenChange']) const className = ref(props.className) const state = ref({ oldList: [], newList: [], tableData: [], tableConfig: [] }) const currentRow = ref(null) //用于记录被选中的行
const copyData = ref([])

watch(() => props.rowId, (val) => {
    console.log('rowId', val,currentRow.value)
    if(!currentRow.value) return
    if(!val&&currentRow.value) {
        proxy.$refs[props.refsName].setCurrentRow(-1)
        return
    }
    if (val !== currentRow.value.id) {
        proxy.$refs[props.refsName].setCurrentRow(-1)
        return
    }
})
watch(() => props.tableData, (newVal) => {
    if (newVal && newVal.length) {
        state.value.tableData = newVal
        state.value.tableData.forEach(item => {
            item.children.forEach((its, index) => {
                its.serialNumber = item.serialNumber + '.' + (index + 1)
            })
        })
      copyData.value = props.tableData.map(item => item)
    }
})

// 行拖拽
const rowDrop = function (name) {
    // 要拖拽元素的父容器
  // 寻找指定的class
const tbody = document.querySelector(`.${name} tbody`); Sortable.create(tbody, { // dragClass: "dragClass", //设置拖拽样式类名 ghostClass: "ghostClass", //设置拖拽停靠样式类名 // chosenClass: "chosenClass", //设置选中样式类名 // 可被拖拽的子元素 draggable: ".draggable .el-table__row", onEnd({ newDraggableIndex, oldDraggableIndex }) {

           const currRow = copyData.value[oldDraggableIndex]
                const nextItem = copyData.value[newDraggableIndex];
                let type = ''
                if (!currRow) return
                let num = newDraggableIndex - oldDraggableIndex
                if (num > 0) {
                    type = 'after'
                    console.log('after 在目标位置之后', nextItem)
                } else if (num == 0) {
                    return
                } else {
                    type = 'before'
                    console.log('brfore 在目标位置之前', nextItem)
                }
            copyData.value.splice(oldDraggableIndex, 1)
                    copyData.value.splice(newDraggableIndex, 0, currRow)
                    state.value.tableData = copyData.value

        }
    });
}
// 列拖拽
const columnDrop = function () {
    const wrapperTr = document.querySelector('.draggable .el-table__header-wrapper tr');
    Sortable.create(wrapperTr, {
        animation: 180,
        delay: 0,
        onEnd: evt => {
            const oldItem = state.value.newList[evt.oldIndex];
            state.value.newList.splice(evt.oldIndex, 1);
            state.value.newList.splice(evt.newIndex, 0, oldItem);
        }
    });
}
// 行点击
const handleCurrentClick = (val) => {
    if(val == -1) return
    console.log('行点击', val)
    currentRow.value = val
    emit('childrenChange', val)
}
// 子表格行点击
const childrenClick = (data) => {
    console.log('子表格行点击', data)
    if(data == -1) return
    if(!currentRow.value) {
        emit('childrenChange', data)
        return
    }
    if(data.id !== currentRow.value.id) {
        proxy.$refs[props.refsName].setCurrentRow(-1)
        emit('childrenChange', data)
        return
    }
}
onMounted(() => {
    state.value.tableConfig = props.tableConfig
    state.value.oldList = props.tableConfig
    state.value.newList = props.tableConfig
    state.value.tableData = props.tableData
    copyData.value = props.tableData
    columnDrop(props.className)
    rowDrop(props.className)
})
</script>
<style>
/* .dragClass {
  background: #41c21a !important;
} */
/* 停靠 */
.ghostClass {
    background: rgba(64, 158, 255, 0.2) !important;
}

/* 选择 */
/* .chosenClass:hover > td {
  background: #f56c6c !important;
} */
</style>

示例数据:

const tableData = [{
    date: '2016-05-02',
    name: '王小虎',
    address: '上海市普陀区金沙江路 1518 弄'
  }, {
    date: '2016-05-04',
    name: '王小虎',
    address: '上海市普陀区金沙江路 1517 弄'
  }, {
    date: '2016-05-01',
    name: '王小虎',
    address: '上海市普陀区金沙江路 1519 弄'
  }, {
    date: '2016-05-03',
    name: '王小虎',
    address: '上海市普陀区金沙江路 1516 弄'
  }]
const tableConfig = ref([
    {
        label: '名称',
        prop: 'name',
    }
])

 

 
posted @ 2023-08-24 11:35  月亮已落  阅读(287)  评论(0)    收藏  举报