el-tree树形控件的增删改查

<template>
    <div>
        <el-row style="height: 70vh; overflow: auto">
            <el-col :span="6" style="padding-right: 10px; border-right: 2px solid #ccc; height: 100%">
                <el-input placeholder="输入关键字进行过滤" v-model="filterText" clearable style="margin-bottom: 10px;">
                </el-input>
                <el-tree :data="treeData" :props="defaultProps" :expand-on-click-node="false"
                    :filter-node-method="filterNode" node-key="id" ref="tree" default-expand-all
                    @node-click="handleNodeClick">
                    <span class="custom-tree-node show-hide" slot-scope="{ node, data }"
                        :ref="'node_' + data.contentId">
                        <template v-if="!data.isEdit">
                            <span>{{ node.label }}</span>
                            <span style="display:none">
                                <i @click="() => appendNode(node, data)" class="el-icon-plus"
                                    style="margin-right: 10px;" title="增加"></i>
                                <!-- 根节点不需要删除和修改 -->
                                <i v-if="data.level != 1" @click="() => removeNode(node, data)" class="el-icon-delete"
                                    style="margin-right: 10px;" title="删除"></i>
                                <i v-if="data.level != 1" @click="data.isEdit = true" class="el-icon-edit"
                                    title="编辑"></i>
                            </span>
                        </template>
                        <template v-else class="editContainer">
                            <el-input v-model="data.label" style="margin-right: 10px;" clearable :autofocus="true"
                                placeholder="请输入新节点名称"></el-input>
                            <i @click="() => editNode(node, data)" class="el-icon-circle-check"
                                style="margin-right: 10px;" title="确定"></i>
                            <i @click="() => removeNode(node, data)" class="el-icon-delete" title="删除"></i>
                        </template>

                    </span>
                </el-tree>
            </el-col>
        </el-row>
    </div>
</template>

 

<script>
import { listBridgefilecontent, getBridgefilecontent, delBridgefilecontent, addBridgefilecontent, updateBridgefilecontent } from "@/api/bridge/bridgefilecontent";
import { listBridgefiledetail, getBridgefiledetail, delBridgefiledetail, addBridgefiledetail, updateBridgefiledetail } from "@/api/bridge/bridgefiledetail";

export default {
    data() {
        return {
            filterText: '',
            defaultProps: {
                children: 'children',
                label: 'label'
            },
            treeData: [],
        }
    },
    watch: {
        filterText: {
            handler(val, oldVal) {
                // console.log(val, oldVal);
                this.$refs.tree.filter(val);
            }
        },
    },
    created() {
    },
    methods: {
        handleAdd() {
            if (this.isClickNode) {
                this.open = true;
            } else {
                this.$modal.msgError("请选择节点");
            }
        },
        editNode(node, data) {
            console.log(node);
            console.log(data);
            updateBridgefilecontent({
                bridgeId: this.bridgeId,
                contentId: data.contentId,
                parentId: data.parentId,
                level: data.level,
                label: data.label ? data.label : "新节点",
            }).then(res => {
                if (res.code === 200) {
                    this.getTreeselect();
                    // this.msgSuccess("修改成功");
                }
            })
        },
        filterNode(value, data) {
            if (!value) return true;
            return data.label.indexOf(value) !== -1;
        },
        handleNodeClick(data) {
            console.log(data);
        },
        async getTreeselect() {
            await listBridgefilecontent({ bridgeId: this.bridgeId }).then(res => {
                if (res.code === 200) {
                    this.treeData = [];
                    console.log(res.data)
                    if (res.data.length === 0) {
                        addBridgefilecontent({
                            bridgeId: this.bridgeId,
                            parentId: 0,
                            label: "文件",
                            level: 1
                        }).then(res => {
                            if (res.code === 200) {
                                this.getTreeselect();
                                // this.msgSuccess("新增成功");
                            }
                        })
                    } else {
                        const nodeMap = {};
                        res.data.forEach(item => {
                            nodeMap[item.contentId] = {
                                ...item,
                                children: [],
                                isEdit: false,
                            };
                        });

                        // 构建树形结构
                        res.data.forEach(item => {
                            const node = nodeMap[item.contentId];
                            const parentId = item.parentId;
                            if (parentId === 0) {
                                this.treeData.push(node);
                            } else {
                                const parent = nodeMap[parentId];
                                if (parent) {
                                    parent.children.push(node);
                                }
                            }
                        });
                        console.log(this.treeData);
                    }
                    // this.data = res.data;
                }
            });
        },
        // 新增树节点
        appendNode(node, data) {
            console.log("新增节点", node, data);

            addBridgefilecontent({
                bridgeId: this.bridgeId,
                parentId: Number(data.contentId),
                label: "",
                level: Number(data.level) + 1
            }).then(async res => {
                if (res.code === 200) {
                    await this.getTreeselect();
                    this.$nextTick(() => {
                        console.log(res.data);
                        const newNode = this.findNewNode(this.treeData, res.data);
                        console.log(newNode);
                        if (newNode) {
                            newNode.isEdit = true;
                        }
                    })
                }
            })
        },
        // 递归查找新增的节点
        findNewNode(nodes, contentId) {
            console.log(nodes, contentId);
            for (const node of nodes) {
                if (node.contentId === contentId) {
                    return node;
                }
                if (node.children && node.children.length > 0) {
                    const found = this.findNewNode(node.children, contentId);
                    if (found) {
                        return found;
                    }
                }
            }
            return null;
        },
        // 删除树节点
        removeNode(node, data) {
            // console.log("删除节点", node, data);
            // console.log(this.nodeData)
            let _this = this;
            let ids = [];
            ids.push(data.contentId);
            if (data.children && data.children.length > 0) {
                data.children.forEach(item => {
                    ids.push(item.contentId);
                })
            }
            console.log(ids);
            // return
            this.$confirm("是否确认删除此节点?", "警告", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning",
            }).then(function () {
                console.log(data.contentId, _this.nodeData.contentId);
                if (data.contentId == _this.nodeData.contentId) {
                    _this.isClickNode = false;
                    _this.showData = [];
                    _this.tableData = [];
                    console.log("isClickNode", _this.isClickNode);
                }
                return delBridgefilecontent(ids.join(','));
            }).then(response => {
                if (response.code === 200) {
                    this.getTreeselect();
                    // this.msgSuccess("删除成功");
                } else {
                    this.$message({
                        message: response.msg,
                        type: 'warning'
                    });
                    return;
                }
            })
        },
    }
}
</script>
<style lang='scss' scoped>
.custom-tree-node {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 14px;
    padding-right: 8px;
}

.show-hide:hover :nth-child(2) {
    display: inline-block !important;
}

.editContainer {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

::v-deep .el-input .el-input__inner {
    height: 26px;
}

.verticalLine {
    border-left: 1px solid #ccc;
    border-radius: 40%;
    height: 100%;
    width: 2px;
    margin-left: 25%;
    background-color: #ccc;
}
</style>

 

 

### 使用 Vue 实现树形结构的增删改查 #### 1. Ant Design Vue 中的树形控件实现 在 Ant Design Vue 中,虽然官方提供了基础的 `Tree` 组件用于展示数据,但对于复杂的业务需求如增删改查,则需自行扩展。通过监听事件并结合状态管理可以完成这些操作。 对于增加节点的功能,在点击新增按钮时应打开对话框让用户输入新节点名称,并指定其父节点位置;之后向服务器发送请求保存更改或将新的对象推入本地的数据列表中模拟成功后的效果[^1]。 ```javascript // 新增子节点逻辑示例 const addNode = (parentId, newNodeName) => { const newData = [...treeData]; function traverse(data){ data.forEach(item=>{ if(item.key === parentId){ item.children ? item.children.push({title:newNodeName,key:`${Date.now()}`,children:[]}) : item.children=[{title:newNodeName,key:`${Date.now()}`,children:[]}]; }else{ item.children && traverse(item.children); } }); } traverse(newData); setTreeData([...newData]); } ``` #### 2. Element Plus 的 Tree 组件应用案例 Element Plus 提供了一个更为直观的例子来说明如何利用 `el-tree` 来构建具有 CRUD 功能的应用程序。此例子不仅包含了基本的选择、展开等功能,还特别强调了自定义渲染函数(`render-content`)的重要性,它允许开发者灵活地控制每个节点的内容呈现方式以及交互行为[^2]。 ```html <template> <div> <el-button @click="handleAdd">添加</el-button> <!-- 更多功能按钮 --> <el-tree ref="treeRef" :data="data" show-checkbox node-key="id" default-expand-all :expand-on-click-node="false" :render-content="renderContent"> </el-tree> </div> </template> <script setup lang="ts"> import { h, reactive, ref } from 'vue'; let treeRef=ref(null) function handleAdd(){ // 添加节点的具体实现... } function renderContent(h,{node,data}){ return ( <span class="custom-tree-node"> <span>{node.label}</span> {/* 自定义的操作按钮 */} </span>) } </script> ``` #### 3. Vxe-Table 对于复杂场景的支持 Vxe-Table 是一款强大的表格组件库,除了常规表格特性外也支持创建带有层次关系的数据视图即所谓的“虚拟树”。该框架下的树状结构同样能够方便地集成各种CRUD能力,比如通过右键菜单快速执行编辑或移除动作等高级特性[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值