【sgLazyTree】自定义组件:动态懒加载el-tree树节点数据,实现增删改、懒加载及局部数据刷新。
特性
- 可以自定义主键、配置选项
- 支持预定义节点图标:folder文件夹|normal普通样式
- 多个提示文本可以自定义
- 支持动态接口增删改节点
- 可以自定义根节点Id
- 可以设置最多允许添加的层级深度
sgLazyTree源码
<template><div :class="$options.name" v-loading="rootLoading"><div class="tree-header" v-if="!(readonly || readonly === '')"><div class="sg-left "><template v-if="uploadData"><el-tooltip popper-class="sg-el-tooltip" :enterable="false" effect="dark" :content="`支持拖拽到树上传文件`"placement="top-start"><el-button type="text" icon="el-icon-upload" size="mini"@click="d => $refs.sgUpload.triggerUploadFile()">批量导入</el-button></el-tooltip><el-button type="text" icon="el-icon-download" size="mini" @click="downloadTpl">下载模板</el-button></template></div><div class="sg-right "><el-button type="text" size="mini" @click.stop="addRoot">{{ (data.text || {}).addRootButtonText|| `添加根节点` }}<i class="el-icon-circle-plus-outline"></i></el-button></div></div><div class="tree-container"><el-tree :load="loadNode" lazy ref="tree" :node-key="mainKey" :props="data.props || { label: 'label' }":icon-class="`${data.iconType}-tree-node`" :indent="data.indent || 25" @current-change="current_change"@node-click="nodeClick" highlight-current><el-popover popper-class="tree-el-popover" placement="right" trigger="hover" title="" content="":disabled="readonly || readonly === ''" slot-scope="{ node, data }"><span class="right"><el-button title="添加" type="text" size="" icon="el-icon-circle-plus-outline"@click.stop="addNode(node, data)" v-if="showAddButton(node)">添加</el-button><el-button title="删除" type="text" size="" icon="el-icon-remove-outline"@click.stop="remove(node, data)">删除</el-button></span><div slot="reference" class="node-label"><label class="left" :title="node.label">{{ node.label }}</label></div></el-popover></el-tree><!-- 上传组件 --><sgUpload drag ref="sgUpload" :data="uploadData" @success="uploadSuccess" @error="uploadError" hideUploadTray /></div></div>
</template><script>
import sgUpload from "@/vue/components/admin/sgUpload";
export default {name: 'sgLazyTree',components: {sgUpload,},data() {return {// 动态树:增删改_________________________________________________________rootNode: null,//根节点rootResolve: null,//根节点focusNodeId: null,//聚焦高亮新添加IDrootLoading: false,//根节点列表加载mainKey: 'id',//默认主键defaultRootId: 'root',//默认根节点ID就是rootmaxAddLevel: null,// 最多允许添加的层级// _________________________________________________________}},props: ["data","readonly","uploadData",/* 例子 uploadData: {accept: '.xls,.xlsx',actionUrl: `${this.$d.API_ROOT_URL}/core/resource/upload`,}, */],watch: {data: {handler(d) {d.nodeKey && (this.mainKey = d.nodeKey);//主键d.rootId && (this.defaultRootId = d.rootId);//根节点IDd.maxAddLevel && (this.maxAddLevel = d.maxAddLevel);// 最多允许添加的层级}, deep: true, immediate: true,},},methods: {showAddButton(node) {if (this.maxAddLevel) {return node.level < this.maxAddLevel; // 最多允许添加的层级} else return true;},downloadTpl(d) {this.$emit(`downloadTpl`);},uploadSuccess(d, f) {this.$emit(`uploadSuccess`, d, f);},uploadError(d, f) {this.$emit(`uploadError`, d, f);},// 动态懒加载树:增删改_________________________________________________________// 加载根节点loadRootNode() {this.rootNode.childNodes = [];this.loadNode(this.rootNode, this.rootResolve);},// 加载常规节点loadNode(node, resolve) {let data = {};if (node.level === 0) {data = { [this.mainKey]: this.defaultRootId };this.rootNode = node;//记录根节点this.rootResolve = resolve;//记录根节点} else {data = node.data;}this.loadNodeData(data, d => {resolve(d);this.rootLoading = false;this.$nextTick(() => {this.focusNode(this.focusNodeId)});});},// 加载节点数据(通过接口向后台获取数据)loadNodeData(data, cb) {let resolve = d => { cb && cb(d) };this.$emit(`loadNode`, data, resolve);},// 聚焦到某一个节点focusNode(id) {if (!id) return;this.$nextTick(() => {this.$refs.tree.setCurrentKey(id);//高亮显示某个节点this.$emit(`currentChange`, this.$refs.tree.getCurrentNode());this.$nextTick(() => {let dom = document.querySelector(`.el-tree-node.is-current`);dom && dom.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });//缓慢滚动});});},// 添加根节点addRoot() { this.addNode(this.$refs.tree.root, { [this.mainKey]: this.defaultRootId }) },// 添加节点addNode(node, data) {let isRootNode = data[this.mainKey] === this.defaultRootId;isRootNode && (this.rootLoading = true);let resolve = d => {this.focusNodeId = d[this.mainKey];//记录加载完毕后需要聚焦的节点IDif (isRootNode) {this.loadRootNode();//触发根节点加载} else {node.loaded = false; //必须要设置loaded=false,否则第二次展开节点不会触发加载数据node.expanded ? node.loadData() : node.expand();//如果已展开→触发加载,否则就先展开→触发加载 }};this.$emit(`addNode`, data, resolve);},// 删除节点remove(node, data) {this.$confirm((this.data.text || {}).removeConfirmTip || `此操作将永久删除该节点及其下面的节点,是否继续?`,(this.data.text || {}).removeConfirmTitle || `提示`,{dangerouslyUseHTMLString: true,confirmButtonText: `确定`,cancelButtonText: `取消`,type: "warning",}).then(() => {this.removeNodeData(node, data)}).catch(() => { });},// 删除节点数据(通过接口向后台删除数据)removeNodeData(node, data) {node.loading = true;//出现加载动画let resolve = d => {node.loading = false;this.$message.success(`删除成功`);// 从显示界面删除节点let childNodes = node.parent.childNodes;childNodes.splice(childNodes.findIndex(d => d.data[this.mainKey] === data[this.mainKey]), 1);};this.$emit(`removeNode`, data, resolve);},// 当前选中节点变化时触发的事件current_change(d) { this.$emit(`currentChange`, d); },//点击节点nodeClick(d) { this.focusNodeId = null; this.$emit(`nodeClick`, d); },}
};
</script><style lang="scss" scoped>
@import "~@/css/sg";.sgLazyTree {$treeHeaderHeight: 30px;width: 100%;height: 100%;display: flex;flex-wrap: nowrap;flex-direction: column;white-space: nowrap;flex-shrink: 0;flex-grow: 1;position: relative;.tree-header {display: flex;justify-content: space-between;align-items: center;height: $treeHeaderHeight;&>.sg-left {}&>.sg-right {}}.tree-container {position: relative;overflow: auto;box-sizing: border-box;height: calc(100% - #{$treeHeaderHeight});user-select: none;@include scrollbarHover();>>>.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content {background-color: #409EFF22; // 高亮当前选中节点背景}>>>.el-tree {* {transition: none;}.el-tree-node__children {min-width: max-content; //这样才会出现水平滚动条}.normal-tree-node,.folder-tree-node {flex-shrink: 0;display: block;padding: 0 !important;margin: 0;width: 20px;height: 20px;margin-right: 5px;background: transparent url("/static/img/fileType/folder/folder.svg") no-repeat center / contain;margin-left: 20px;&~span:not(.el-icon-loading) {width: 100%;.node-label {height: 40px;display: flex;align-items: center;}}&.expanded,&.is-leaf {flex-shrink: 0;transform: rotate(0deg);background-image: url("/static/img/fileType/folder/folder-open.svg");}}}}
}.tree-el-popover {.el-button {padding-top: 0;padding-bottom: 0;}
}
</style>
用例
<template><div style="width: 300px;padding-right: 100px;"><sgLazyTree :data="lazyTreeData" @currentChange="currentChange" @loadNode="loadNode"@addNode="addNode" @removeNode="removeNode" /></div>
</template><script>
import sgLazyTree from "@/vue/components/admin/sgLazyTree";
export default {components: { sgLazyTree, },data() {return {autoId: 0,//自增编号lazyTreeData: {nodeKey: `ID`,//主键props: { label: 'MC' },//配置选项iconType: 'folder',//节点图标:folder文件夹|normal普通样式text: {addRootButtonText: '添加根目录',//添加根节点按钮文本removeConfirmTitle: '警告!!!',//删除节点提示标题removeConfirmTip: '此操作将永久删除该文件夹及其下面的文件,是否继续?',//删除节点提示内容},},}},methods: {// 获取当前聚焦节点的数据currentChange(d) {console.log(`currentChange`, d);},// 加载节点数据loadNode(data, resolve) { this.$d.column_queryByPid({ data: { PID: data.ID }, doing: { s: d => resolve(d) } }); },// 添加节点addNode(data, resolve) {this.$d.column_save({data: {MC: `新增栏目名称(${++this.autoId})`,LX: 0, PID: data.ID,//上一级id}, doing: { s: d => resolve(d) }});},// 删除节点removeNode(data, resolve) {this.$d.column_delete({ data: { ID: data.ID }, doing: { s: d => resolve(d) } });},},};
</script>
相关文章:

【sgLazyTree】自定义组件:动态懒加载el-tree树节点数据,实现增删改、懒加载及局部数据刷新。
特性 可以自定义主键、配置选项支持预定义节点图标:folder文件夹|normal普通样式多个提示文本可以自定义支持动态接口增删改节点可以自定义根节点Id可以设置最多允许添加的层级深度 sgLazyTree源码 <template><div :class"$options.name" v-lo…...
Rust个人学习笔记
感悟:感觉rust好像缝合怪,既有python的影子,又有java和cpp的影子,可能这就是新型编程语言趋势吧。而且他的各种规范很严格很规范,比java还更工程,各种规范不对都有warning。 命名规范:蛇形命名…...
Java根据身份证号码提取出省市区,JSON数据格式
package com.rdes.talents.utils;import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern;/*** Author: 更多实用源码 www.cx1314.cn* Date: 2023/9/7 …...

MySQL知识笔记——初级基础(实施工程师和DBA工作笔记)
老生长谈,MySQL具有开源、支持多语言、性能好、安全性高的特点,广受业界欢迎。 在数据爆炸式增长的年代,掌握一种数据库能够更好的提升自己的业务能力(实施工程师)。 此系列将会记录我学习和进阶SQL路上的知识…...
javaee 事务的传播行为
事务的传播行为 事务的第一个方面是传播行为(propagation behavior)。当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的…...

C#-SQLite-使用教程笔记
微软官网资料链接(可下载文档) 教程参考链接:SQLite 教程 - SQLite中文手册 项目中对应的system.dat文件可以用SQLiteStudio打开查看 参考文档:https://d7ehk.jb51.net/202008/books/SQLite_jb51.rar 总结介绍 1、下载SQLiteS…...

Tomcat详解 一:tomcat的部署
文章目录 1. Tomcat的基本介绍1.1 Tomcat是什么1.2 Tomcat的构成组件1.2.1 Web容器1.2.2 Servlet容器1.2.3 JSP容器(JAVA Scripts page) 1.3 核心功能1.3.1 Container 结构分析 1.4 配置文件1.5 Tomcat常用端口号1.6 启动和关闭Tomcat 2. 部署Tomcat服务…...
算法 - 二分
~~~~ 题目 - 整数二分需要考虑边界思路code开平方 - 浮点数二分codecode core 题目 - 整数二分需要考虑边界 给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。 对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始…...

蠕虫病毒问题
蠕虫病毒处理过程 修改病毒定时时间,今天遇到的是 */30 crontab -e先修改延长时间,会提示无操作权限,执行下面的问题 chattr -l /filepath查看可疑进程,这次遇到的进程有 /tmp/***** /tmp/crontab***** ps -auxkill -9 相关进程 删除/…...

pytest笔记2: fixture
1. fixture 通常是对测试方法和测试函数,测试类整个测试文件进行初始化或是还原测试环境 # 功能函数 def multiply(a, b):return a * b # ------------ fixture---------------def setup_module(module):print("setup_module 在当前文件中所有测试用例之前&q…...

day55 补
392.判断子序列 力扣题目链接(opens new window) 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,&quo…...
CSS变量之var()函数的应用——动态修改样式 root的使用
一、css变量 body {--foo: #7F593F;--urls: ./img/xxx.jpg; }变量的名称可以用数字、汉字等,不能包含**$,[,^,(,%**等字符,变量的值也是可以使用各种属性值: 如: // 定义css变量 :r…...

索尼 toio ™应用创意开发征文|一个理想的绘画小助手
引言 toio™机器人是索尼推出的一款创意玩具,它的小巧和可编程性使其成为一个理想的绘画助手。通过编程控制机器人的运动和绘画工具,我们可以为小朋友提供一个有趣的绘画体验。 创意描述 我们可以通过JavaScript编程来控制toio™机器人的运动和绘画工具…...
java加密,使用python解密 ,使用 pysm4 报 byte greater than 16的解决方法
1,业务需要,对方需要用java进行参数加密,双方约定使用的加密方法是 SM4,对方给的key是32位,并且给出了加解密的java代码。 import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.Key; i…...
django后台启动CORS跨越配置
文章目录 背景什么是跨域问题?跨域问题的解决方案 Django 解决跨域问题 背景 什么是跨域问题? 跨域问题是指浏览器的同源策略限制了来自不同域的 AJAX 请求。 具体来说: 同源策略要求源相同才能正常进行 AJAX 通信。判断是否同源需要满足三个条件: 协…...

异常的顶级理解
目录 1.异常的概念与体系结构 1.1异常的体系结构 1.2异常的举例 1.3错误的举例 2.异常的分类 2.1编译时异常 2.2运行时异常 3.异常的处理 3.1异常的抛出throw 3.2try-catch捕获并处理 3.3finally 3.4 异常声明throws 4.自定义异常类 1.异常的概念与体系结构 1.1异常的…...
LinkedHashMap实现LRU缓存cache机制,Kotlin
LinkedHashMap实现LRU缓存cache机制,Kotlin LinkedHashMap的accessOrdertrue后,访问LinkedHashMap里面存储的元素,LinkedHashMap就会把该元素移动到最尾部。利用这一点,可以设置一个缓存的上限值,当存入的缓存数理超过…...
Google 开源库Guava详解(集合工具类)
任何具有JDK Collections Framework经验的程序员都知道并喜欢java.util.Collections.Guava提供了更多的实用程序:适用于所有集合的静态方法。这些是番石榴最受欢迎和成熟的部分。 对应于特定接口的方法以相对直观的方式分组: nterface JDK or Guava? …...

Ansys Zemax | 如何将光线追迹结果导出为IES格式
照明系统设计者通常需要向客户提供IES格式的数据。照明工程学会 (Illuminating Engineering Society,IES) 文件格式便于传输辉度数据,该格式得到了制造商和设计师的广泛认可。本文描述了如何生成IES文件并验证结果。(联系我们获取文章附件&am…...
JSONObject 比 Map好使的地方
需求:改originalJson中的json字符串的key,当key满足在configMapping中配置的key2情况的时候,把originalJson的key改成 configMapping中的value2。 上代码: import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject;p…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...