【vue】el-tree的新增/编辑/删除节点

news/2024/10/20 3:45:06/

1、概述

关于树形结构的新增同级节点新增子级节点修改节点名称删除节点等四种操作,各种参数配置完全继承el-tree,本篇使用vue2 + element-ui

2、效果图展示

3、调用方式

javascript"><template><Tree:data="treeData":props="defaultProps":default-expanded-keys="expandedKeys"node-key="id"highlight-current:highligh-color="highlighColor":show-btn-group="showBtnGroup":draggable="true"@node-click="nodeClick"@editNodeSubmit="addNode"@deleteNodeSubmit="deleteNode"@node-drag-end="handleDragEnd"/>
</template>      <script>
export default {name: 'Tree',data() {return {defaultProps: {children: 'children',label: 'label'},expandedKeys: [], // 展开节点highlighColor: {color: '#FFAE0D',bgColor: 'rgba(255, 174, 13, .1)'},showBtnGroup: true,treeData: []}}
}
</script>

4、源码解析

javascript"><template><el-treeref="tree":class="['menu-el-tree',iconStyle.src && 'menu-expand-icon',highlighColor && 'menu-node-highligh']":style="{'--bgUrl': 'url(' + iconStyle.src + ')','--iconWidth': iconStyle.width,'--iconHeight': iconStyle.height,'--iconTransform': iconStyle.transform,'--hoverColor': hoverStyle.color,'--hoverBgColor': hoverStyle.bgColor,'--highlighColor': highlighColor.color,'--highlighBgColor': highlighColor.bgColor}"node-key="id":draggable="draggable"v-bind="$attrs"v-on="$listeners"><template v-slot="{ node, data }"><div v-if="!data.isEdit" class="custom-tree-node-root" @mouseenter="nodeMouseEnter(node)" @mouseleave="nodeMouseLeve(node)"><span class="custom-tree-node">{{ node.label }}</span><section v-show="node.showBtn" class="tree-btn-group"><el-tooltipv-for="item in btnGroup":key="item"effect="light"placement="top"popper-class="common-tooltip-primary":content="{'addChild': '新增子级','delete': '删除','edit': '修改','addSibling': '新增同级'}[item]"><i:class="{'addChild': 'el-icon-circle-plus-outline','delete': 'el-icon-circle-close','edit': 'el-icon-edit','addSibling': 'el-icon-plus'}[item]"@click.stop="() => handleOperaion(item, node, data)"/></el-tooltip></section></div><div v-else class="custom-tree-node-root-edit"><el-input v-model="inputValue" :size="editInputStyle.size" :style="{ width: editInputStyle.width }" /><section :id="data.id"><el-tooltipcontent="确定"popper-class="common-tooltip-primary"effect="light"placement="top"><i class="el-icon-success" @click.stop="() => editMenuSubmit(node, data)" /></el-tooltip><el-tooltipcontent="取消"popper-class="common-tooltip-primary"effect="light"placement="top"><i class="el-icon-error" @click.stop="() => addSiblingCancel(node, data)" /></el-tooltip></section></div></template></el-tree>
</template>
<script>
export default {name: 'MenuTree',inheritAttrs: true,props: {hoverStyle: {type: Object,default: () => ({color: '#606266',bgColor: '#F5F7FA'})},/*** @description 当前行选中高亮颜色配置*/highlighColor: {type: Object,default: () => ({color: '#606266',bgColor: '#fff9ec'})},/*** @description 动态左侧图标配置(图片格式)*/iconStyle: {type: Object,default: () => ({src: '',width: '20px',height: '17px',transform: 'rotate(270deg)'})},/*** @description 操作按钮组* addChild => 新增子级,delete => 删除, edit => 修改, addSibling => 新增同级*/btnGroup: {type: Array,default: () => ['edit', 'addSibling', 'addChild', 'delete']},/*** @description 是否展示操作按钮*/showBtnGroup: {type: Boolean,default: false},/*** @description 编辑模式输入框样式*/editInputStyle: {type: Object,default: () => ({size: 'mini',width: '200px'})},/*** 是否可拖拽*/draggable: {type: Boolean,default: false}},data() {return {inputValue: ''}},methods: {/*** @description 鼠标移入目录层级*/nodeMouseEnter(data) {if (!this.showBtnGroup) return;this.$set(data, 'showBtn', true)},/*** @description 鼠标移除目录层级*/nodeMouseLeve(data) {if (!this.showBtnGroup) return;this.$set(data, 'showBtn', false)},/*** 当前目录操作分发* @param {string} eventKey 事件名称* @param {object} currentNode 当前Node节点内容* @param {object} data 当前节点数据*/handleOperaion(eventKey, currentNode, data) {console.log(currentNode, data, 'menuRoot');switch (eventKey) {case 'addSibling':this.addSibling(currentNode, data);break;case 'edit':this.editTreeItem(data);break;case 'addChild':this.addChild(currentNode, data);break;case 'delete':this.deleteTreeItem(currentNode, data);break;}},/*** @description 编辑当前节点*/editTreeItem(data) {this.$set(data, 'isEdit', true);this.inputValue = data.label; // 当前正在编辑内容赋值this.$nextTick(() => {document.getElementById(data.id).previousElementSibling.firstElementChild.focus();})},/*** @description 添加同级节点*/addSibling(currentNode, data) {const treeDOM = this.$refs.tree;const id = Math.ceil(Math.random() * 100)const newData = { id: id, pId: data.pId, label: '', isEdit: true, isNew: true, children: [] };treeDOM.insertAfter(newData, currentNode);// 聚焦当前新增目录this.$nextTick(() => {document.getElementById(newData.id).previousElementSibling.firstElementChild.focus();})},/*** @description 添加子级节点*/addChild(currentNode, data) {const treeDOM = this.$refs.tree;const id = Math.ceil(Math.random() * 100)const newData = { id: id, pId: data.id, label: '', isEdit: true, isNew: true, children: [] };treeDOM.append(newData, currentNode);// 展开子节点后才能获取DOM聚焦treeDOM.store.nodesMap[data.id].expanded = true;setTimeout(() => {document.getElementById(newData.id).previousElementSibling.firstElementChild.focus();}, 500)},/*** @description 编辑模式修改确认*/editMenuSubmit(node, data) {this.$emit('editNodeSubmit', {node,data,currentLabel: this.inputValue,// 新增同级/子级节点接口调用成功的话,即新增同级/子级节点callback: (status) => {if (status) {this.resetNode()}}});},/*** @description 删除当前节点*/deleteTreeItem(node, data) {this.$emit('deleteNodeSubmit', {node,data,callback: (status) => {// 删除接口调用成功的话,即删除节点if (status) {const treeDOM = this.$refs.tree;treeDOM.remove(node);}}});},/*** @description 取消同级节点添加*/addSiblingCancel(node, data) {// 如果是新增的节点,取消即是删除if (data.isNew) {const treeDOM = this.$refs.tree;treeDOM.remove(node);} else {// 重置修改内容this.inputValue = '';data.isEdit = false;}},/*** 寻找第一个叶子节点及叶子节点的父节点* @param {*} tree 平铺数组*/findFirstChildAndParent(tree) {let firstChild = null;let parentOfFirstChild = null;const dfs = (node, parent) => {if (firstChild !== null) {return; // 如果已经找到了第一个子节点,则不再继续搜索}if (node.children && node.children.length > 0) {// eslint-disable-next-linefor (const child of node.children) {dfs(child, node);}} else {firstChild = node;parentOfFirstChild = parent;}}// eslint-disable-next-linefor (const node of tree) {dfs(node, null);}return {firstChild,parentOfFirstChild};},/*** 获取自身树结构实例*/getTree() {return this.$refs.tree;},/*** 重置节点数据*/resetNode() {this.inputValue = '';},/*** 寻找节点对应的父级节点* @param {*} tree* @param {*} nodeId*/findParentByChildId(tree, nodeId) {let parentOfFirstChild = null;const dfs = (node, parent) => {if (parentOfFirstChild !== null) {return;}if (node.children && node.children.length > 0) {// eslint-disable-next-linefor (const child of node.children) {dfs(child, node);}} else {// 找到对应节点后,返回其父节点if (node.id === nodeId) {parentOfFirstChild = parent;}}}// eslint-disable-next-linefor (const node of tree) {dfs(node, null);}return parentOfFirstChild}}
}
</script>
<style scoped lang="scss">
// 动态配置右侧图标
.menu-expand-icon {::v-deep .el-tree-node__expand-icon:not(.is-leaf) {&::before {background: var(--bgUrl);background-size: contain;background-repeat: no-repeat;background-position: center;content: '';width: var(--iconWidth);height: var(--iconHeight);display: inline-block;transform: var(--iconTransform);}}
}
// 动态配置hover样式
.menu-el-tree {::v-deep .el-tree-node__content {&:hover {background: var(--hoverBgColor);color: var(--hoverColor);}}.custom-tree-node-root {display: flex;align-items: center;flex: 1;.tree-btn-group {margin-left: 15px;display: flex;align-items: center;column-gap: 8px;i {font-size: 15px;&:hover {color: $primary}}}}
}
.menu-node-highligh.el-tree--highlight-current {::v-deep .el-tree-node.is-current>.el-tree-node__content {background: var(--highlighBgColor);color: var(--highlighColor);}
}
.custom-tree-node-root-edit {display: flex;align-items: center;.el-input, ::v-deep .el-input .el-input__inner {height: 26px;}section {i {margin-left: 10px;font-size: 15px;color: $primary;}}
}
</style>

5、疑难解答

1、拖拽节点时,如何监听和区分拖拽事件?

使用的是el-tree内置的node-drag-end事件,当拖拽完成时触发,抛出四个参数

* @param {*} draggingNode 被拖拽的节点

 * @param {*} dropNode 最后进入的节点

 * @param {*} dropType 相对比的位置

 * @param {*} ev 事件

2、新增和删除节点,如何再触发后端接口后再执行节点的新增和删除?

节点新增和删除执行下列两个事件

@editNodeSubmit="addNode"

@deleteNodeSubmit="deleteNode"

他们回调的最后一个参数都是callback,当callback(true)传入为true时,则代表接口成功,则进行后续的树节点操作。

------有不懂的或建议欢迎直接评论噢~------


http://www.ppmy.cn/news/1427524.html

相关文章

ppt技巧:​如何将两个PPT幻灯片文件合并成一个?

第一种方式&#xff1a;复制粘贴幻灯片 1. 打开第一个PPT幻灯片文件&#xff0c;确保你已经熟悉该文件的内容和布局。 2. 打开第二个PPT幻灯片文件&#xff0c;浏览其中的所有幻灯片&#xff0c;选择你想要合并到第一个文件中的幻灯片。 3. 使用快捷键CtrlC&#xff08;Wind…

书生·浦语大模型实战营Day05LMDeploy 高阶

书生浦语大模型实战营Day05LMDeploy 高阶 拓展高阶 使用LMDeploy运行视觉多模态大模型llava 最新版本的LMDeploy支持了llava多模态模型&#xff0c;下面演示使用pipeline推理llava-v1.6-7b。注意&#xff0c;运行本pipeline最低需要30%的InternStudio开发机&#xff0c;请完…

【Python图像处理篇】opencv中的去畸变

去畸变 opencv opencv-python光学畸变校准 使用pythonopencv进行图像的去畸变 使用pythonopencv进行图像的去畸变 关于OpenCV中的去畸变 为什么相机参数每次标定的结果都不一样&#xff08;原理分析&#xff09;

分类预测 | Matlab实现SCSO-SVM沙猫群优化算法优化支持向量机多特征分类预测

分类预测 | Matlab实现SCSO-SVM沙猫群优化算法优化支持向量机多特征分类预测 目录 分类预测 | Matlab实现SCSO-SVM沙猫群优化算法优化支持向量机多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现SCSO-SVM沙猫群优化算法优化支持向量机多特征分类…

如何进行数据库的迁移与同步——【DBA 从入门到实践】第四期

在日常的数据库运维工作中&#xff0c;我们时常会面临数据库替换、机房搬迁、业务测试以及数据库升级等任务&#xff0c;这些任务都需要对数据进行迁移和同步操作。【DBA 从入门到实践】第4期&#xff0c;将引导大家深入了解数据库迁移的流程&#xff0c;并探讨在迁移过程中可用…

【1425】java 外籍人员管理系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目

一、源码特点 java 外籍人员管理系统是一套完善的java web信息管理系统 采用serlvetdaobean&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式 开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff…

3DGS渐进式渲染 - 离线生成渲染视频

总览 输入&#xff1a;环绕Object拍摄的RGB视频 输出&#xff1a;自定义相机路径的渲染视频&#xff08;包含渐变效果&#xff09; 实现过程 首先&#xff0c;编译3DGS的C代码&#xff0c;并跑通convert.py、train.py和render.py。教程如下&#xff1a; github网址&#xf…

openssl3.2 - exp - 用base64后的字符串作为配置项的值

文章目录 openssl3.2 - exp - 用base64后的字符串作为配置项的值概述笔记配置项的值长度有限制 配置项的值不能是base64之后的直接值&#xff0c;需要处理之后才行。openssl配置项的值并不是所有可见字符都可以例子现在用的base64的类cipher_base64.hcipher_base64.cpp 现在用的…