基于vue2+element 实现左向右两个树形tree的跨树拖拽?

<template>
    <div>
        <el-dialog title="编辑转换" :fullscreen="true" ref="dialog" :close-on-click-modal="false"
            :close-on-press-escape="false" :visible.sync="mappingDialog">
            <el-row>
                <el-col :span="10">
                    <el-tree :data="treeData1" ref="treeIn" class="tree" node-key="id" default-expand-all draggable
                        :props="defaultProps" :allow-drag="returnTrue" :render-content="renderTreeNode"
                        @node-drag-start="handleDragstart" @node-drag-end="handleInDragend"></el-tree>
                </el-col>
                <el-col :span="4">
                </el-col>
                <el-col :span="10">
                    <el-tree :data="treeData2" ref="treeOut" class="tree" node-key="id" default-expand-all draggable
                        :props="defaultProps" :allow-drop="returnTrue" :render-content="renderTreeNode"
                        @node-drag-end="handleOutDragEnd"
                                @node-drag-over="handleDragOver"
        @node-drag-leave="handleDragLeave"
                        @node-drop="handleDrop"></el-tree>
                        <!-- is-drop-inner -->
                </el-col>
            </el-row>
            <span slot="footer" class="dialog-footer">
                <el-button @click="handleClose()">取 消</el-button>
                <el-button class="new_btn_class" type="primary" @click="submit">确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>
<script>
export default {
    name: 'schemaModal',
    data() {
        return {
            jsonData: '',
            mappingDialog: false,
            defaultProps: {
                children: 'children',
                label: 'label'
            },
            treeData1: [{
                id: 1,
                label: "一级",
                children: [{
                    id: 4,
                    label: "二级-1111",
                    isFile: true,
                }, {
                    id: 5,
                    label: "二级-2222",
                    isFile: true,
                }],
            }],
            treeData2: [{
                id: 2,
                label: "一级-2222",
                children: [{
                    id: 6,
                    label: "二级-3333",
                    isFile: true,
                },
                {
                    id: 7,
                    label: "二级-4444",
                    isFile: true,
                }],
            }],
        }
    },
    methods: {
        init(args) {
            this.mappingDialog = true;
            console.log(args, 123);
            this.treeData1 = [{
                id: 1,
                label: "一级",
                children: [{
                    id: 4,
                    label: "二级-1111",
                    isFile: true,
                }, {
                    id: 5,
                    label: "二级-2222",
                    isFile: true,
                }],
            }]
            this.treeData2= [{
                id: 2,
                label: "一级-2222",
                children: [{
                    id: 6,
                    label: "二级-3333",
                    isFile: true,
                },
                {
                    id: 7,
                    label: "二级-4444",
                    isFile: true,
                }],
            }]
        },
        handleClose() {
            this.mappingDialog = false;
        },
        submit() {
            console.log(this.treeData2)
        },
        renderTreeNode(h, { node, data, store }) {
            if (data.isFile) {
                return <span><i class="el-icon-document"></i> {data.label}</span>;
            } else {
                return <span><i class="el-icon-folder"></i> {data.label}</span>;
            }
        },
        //左侧节点触发拖拽
        handleDragstart(node, event) {
            console.log('start', node, event)
            //在左侧节点触发拖拽的时候触发右侧节点的拖拽事件
            this.$refs.treeOut.$emit('tree-node-drag-start', event, { node: node });
        },
        //拖拽结束,但是确定是否成功
        handleInDragend(draggingNode, endNode, position, event) {
            console.log('end', draggingNode, endNode, position, event)
            // 新的空节点
            let newData = { id: (+new Date), children: [] };
            //在左tree插入拖拽的节点
            this.$refs.treeIn.insertBefore(newData, draggingNode);
            //右tree触发结束拖拽事件
            this.$refs.treeOut.$emit('tree-node-drag-end', event);
            this.$nextTick(() => {
                // 如果是移动到了自身---
                console.log(this.$refs.treeIn.getNode(draggingNode.data))
                if (this.$refs.treeIn.getNode(draggingNode.data)) {
                    this.$refs.treeIn.remove(newData);
                    console.log('移动到自身')
                } else {
                    // 如果移动到了右tree上----
                    let data = JSON.parse(JSON.stringify(draggingNode.data));
                    this.$refs.treeIn.insertAfter(data, this.$refs.treeIn.getNode(newData));
                    this.$refs.treeIn.remove(newData);
                    console.log('移动到别的tree')
                }
            })
        },
        handleOutDragEnd(draggingNode, endNode, position, event) {
            // console.log('endOut', draggingNode, endNode, position, event)
        },
        handleDragOver({event}) {
            // 阻止默认事件,允许放置
            event.preventDefault();
        },
        handleDragLeave({event}) {
            // 清除放置效果
            event.preventDefault();
        },
        //结束拖拽,可得到拖拽来源与去向
        handleDrop(draggingNode, dropNode, dropType, ev) {
            // const dragNodeData = this.dragNode.data;
            // event.preventDefault();
            console.log('移动结束', draggingNode, dropNode, dropType);
        },
        returnTrue() {
            return true;
        },
        returnFalse() {
            return false;
        }
    }
}
</script>

页面显示图
image.png
想做成的页面显示图,只想知道二级-2222拖动到了二级-4444 并重新赋值
image.png

阅读 1.6k
avatarAI BotBETA

在Vue2和Element UI中实现两个树形控件(Tree)之间的跨树拖拽,主要涉及到监听拖拽事件并正确地在两个树之间移动节点。在你的代码中,你已经设置了一些基本的事件监听,但有几个地方需要调整以确保节点可以正确地从一个树移动到另一个树。

首先,我们需要确保拖拽的节点在handleDrop方法中能够正确地被添加到目标树中,并从源树中移除。此外,你的handleInDragend方法中的逻辑有些混乱,因为它试图在拖拽结束时插入一个空的节点,这在跨树拖拽的场景中并不适用。

以下是修改后的关键部分代码:

1. 移除handleInDragend中不必要的逻辑

因为拖拽结束时的逻辑将在handleDrop中处理,我们可以简化handleInDragend方法:

handleInDragend(draggingNode, endNode, position, event) {
    // 这里可以留空,或者添加一些清理工作
    console.log('Drag ended on source tree', draggingNode);
}

2. 完善handleDrop方法

handleDrop方法中,我们需要判断拖拽的节点是否来自另一个树,如果是,则将其添加到目标树,并从源树中移除。这里的关键是使用draggingNode.data来获取节点数据,并在两个树的数据结构中操作。

handleDrop(draggingNode, dropNode, dropType, ev) {
    ev.preventDefault(); // 阻止默认行为
    if (draggingNode.componentOptions.Ctor.options.name === 'ElTreeNode' && dropNode.componentOptions.Ctor.options.name === 'ElTreeNode') {
        // 跨树拖拽
        const sourceTree = draggingNode.context.$refs.treeIn === draggingNode.$el.closest('.el-tree') ? 'treeIn' : 'treeOut';
        const targetTree = dropNode.context.$refs.treeIn === dropNode.$el.closest('.el-tree') ? 'treeIn' : 'treeOut';

        if (sourceTree !== targetTree) {
            // 从源树中移除节点
            this.$refs[sourceTree].remove(this.$refs[sourceTree].getNode(draggingNode.data));
            // 将节点添加到目标树
            if (dropType === 'before' || dropType === 'after') {
                // 插入到兄弟节点之前或之后
                this.$refs[targetTree].insertBefore(draggingNode.data, this.$refs[targetTree].getNode(dropNode.data), dropType === 'after');
            } else if (dropType === 'inner') {
                // 插入为子节点
                if (!dropNode.data.children) {
                    dropNode.data.children = [];
                }
                dropNode.data.children.push(draggingNode.data);
            }
        }
    }
}

注意:这里的draggingNode.componentOptions.Ctor.options.name可能不是一个可靠的方式来判断节点是否来自Element UI的ElTreeNode组件,因为Vue组件的选项名(如name)可能会更改或不存在。一个更稳妥的方式是使用其他标识符或属性来判断节点来源。这里只是为了演示逻辑。

3. 确保draggableallow-drop属性正确设置

你已经设置了这些属性,但请确保它们在整个应用中保持一致和正确。

4. 调试和测试

在实际应用中,你可能需要添加更多的错误处理和调试语句来确保一切按预期工作。

通过上述修改,你应该能够实现从一个树到另一个树的跨树拖拽功能。

1 个回答
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏