基于vue2 + sortablejs 实现拖拽,支持element-ui表格树形

246 阅读1分钟

可以建一个mixins文件,可以直接引入组件

需要下载 sortablejs
import Sortable from 'sortablejs'
// 表格拖拽计算逻辑
export default {
    data() {
        return {
            activeRows: [],
            // 展开id
            expandedRowKeys: []
        }
    },
    mounted() {
        this.rowDrop()
    },
    methods: {
        // 修复后的拖拽方法
        rowDrop() {
            this.$nextTick(() => {
                const el = this.$refs.sortableTable.$el.querySelector(
                    '.el-table__body-wrapper tbody'
                )
                if (!el) return

                const _this = this
                Sortable.create(el, {
                    animation: 300,
                    // 拖拽目标
                    handle: '.draggableIcon',
                    // 拖拽类名 可以设置拖拽的背景
                    ghostClass: 'sortable-ghost',
                    onStart() {
                        _this.activeRows = _this.treeToTile(_this.tableData)
                    },
                    onMove({ dragged, related }) {
                        const oldRow = _this.activeRows[dragged.rowIndex]
                        const newRow = _this.activeRows[related.rowIndex]

                        // 不允许跨级拖拽 此处写自己的逻辑(不是树形此处删除即可)
                        if (oldRow.level !== newRow.level || oldRow.parentId !== newRow.parentId) {
                            return false
                        }
                        return true
                    },
                    onEnd({ oldIndex, newIndex }) {
                        document.body.style.backgroundColor = ''
                        if (oldIndex === newIndex) return

                        const movedItem = _this.activeRows[oldIndex]
                        const targetItem = _this.activeRows[newIndex]

                        // 确保是同级移动(不是树形此处删除即可)
                        if (movedItem.level !== targetItem.level) return

                        // 深拷贝数据
                        const newData = JSON.parse(JSON.stringify(_this.tableData))

                        // 从树中移除被拖拽的节点
                        _this.removeNode(newData, movedItem.id)

                        // 将节点插入到新位置
                        _this.insertNode(
                            newData,
                            movedItem,
                            targetItem,
                            newIndex > oldIndex ? 'after' : 'before'
                        )
                        // 更新表格数据
                        _this.tableData = newData
                        if (typeof _this.onEndHand === 'function') {
                            _this.onEndHand(targetItem)
                        }

                        _this.$nextTick(() => {
                            _this.rowDrop()
                        })
                    }
                })
            })
        },

        // 从树中移除节点
        removeNode(tree, id) {
            for (let i = 0; i < tree.length; i++) {
                if (tree[i].id === id) {
                    tree.splice(i, 1)
                    return true
                }
                if (tree[i].children && tree[i].children.length > 0) {
                    if (this.removeNode(tree[i].children, id)) {
                        return true
                    }
                }
            }
            return false
        },

        // 将节点插入到树中指定位置
        insertNode(tree, node, targetNode, position = 'after') {
            for (let i = 0; i < tree.length; i++) {
                if (tree[i].id === targetNode.id) {
                    if (position === 'before') {
                        tree.splice(i, 0, node)
                    } else {
                        tree.splice(i + 1, 0, node)
                    }
                    return true
                }
                if (tree[i].children && tree[i].children.length > 0) {
                    if (this.insertNode(tree[i].children, node, targetNode, position)) {
                        return true
                    }
                }
            }
            return false
        },

        // 原有方法保持不变
        treeToTile(treeData, childKey = 'children') {
            const arr = []
            const expanded = (data) => {
                if (data && data.length > 0) {
                    data
                        .filter((d) => d)
                        .forEach((e) => {
                            arr.push(e)
                            expanded(e[childKey] || [])
                        })
                }
            }
            expanded(treeData)
            return arr
        },

        // 折叠展开id处理
        handleExpandChange(row, expanded) {
            if (expanded) {
                // 展开行
                if (!this.expandedRowKeys.includes(row.id)) {
                    this.expandedRowKeys.push(row.id)
                }
            } else {
                // 折叠行
                this.expandedRowKeys = this.expandedRowKeys.filter(
                    (key) => key !== row.id
                )
            }
        },
        // row-key
        getRowKey(item) {
            return item.id
        },
    },
}