vue2 , el-select 多选树结构,可重名
人家antd都支持,elementplus 也支持,vue2的没有,很烦。
网上其实可以搜到各种的,不过大部分不支持重名,在删除的时候可能会删错,比如树结构1F的1楼啊,2F的1楼啊这种同时勾选的情况。。
可以全路径
干净点不要全路径也可以,
一股脑全放,可能有一点无效代码,懒得删了,等出bug再说
<template><!-- <t-tree-select:options="treeList"placeholder="请选择tree结构"width="50%":defaultData="defaultValue":treeProps="treeProps"@handleNodeClick="selectDrop"
/> --><el-selectref="select"v-model="displayValues":multiple="multiple":filter-method="dataFilter"@remove-tag="removeTag"@clear="clearAll"popper-class="t-tree-select":style="{width: width||'100%'}"v-bind="attrs"v-on="$listeners" popper-append-to-bodyclass="select-tree"><el-option v-model="selectTree" class="option-style" disabled ><div class="check-box" v-if="multiple&&checkBoxBtn"><el-button type="text" @click="handlecheckAll">{{checkAllText}}</el-button><el-button type="text" @click="handleReset">{{resetText}}</el-button><el-button type="text" @click="handleReverseCheck">{{reverseCheckText}}</el-button></div> <el-tree:data="options":props="treeProps"class="tree-style"ref="treeNode":check-strictly="true":show-checkbox="multiple":node-key="treeProps.value":filter-node-method="filterNode":default-checked-keys="defaultValue":current-node-key="currentKey"@node-click="handleTreeClick"@check-change="handleNodeChange"v-bind="treeAttrs"v-on="$listeners"></el-tree></el-option></el-select>
</template><script>
export default {name: 'TTreeSelect',props: {// 多选默认值数组defaultValue: {type: Array,default: () => []},// 单选默认展示数据必须是{id:***,label:***}格式defaultData: {type: Object},// 全选文字checkAllText: {type: String,default: '全选'},// 清空文字resetText: {type: String,default: '清空'},// 反选文字reverseCheckText: {type: String,default: '反选'},// 可用选项的数组options: {type: Array,default: () => []},// 配置选项——>属性值为后端返回的对应的字段名treeProps: {type: Object,default: () => ({value: 'value', // ID字段名label: 'title', // 显示名称children: 'children' // 子级字段名})},// 是否显示全选、反选、清空操作checkBoxBtn: {type: Boolean,default: false},// 是否多选multiple: {type: Boolean,default: true},// 选择框宽度width: {type: String},// 是否显示完整路径, 如 1楼-1f-101showFullPath: {type: Boolean,default: true}},data() {return {selectTree: this.multiple ? [] : '', // 绑定el-option的值currentKey: null, // 当前选中的节点filterText: null, // 筛选值VALUE_NAME: this.treeProps.value, // value转换后的字段VALUE_TEXT: this.treeProps.label, // label转换后的字段selectedNodes: [] // 存储选中的完整节点信息}},computed: {attrs() {return {'popper-append-to-body': false,clearable: true,filterable: true,...this.$attrs}},// tree属性treeAttrs() {return {'default-expand-all': true,...this.$attrs}},// 显示值:根据showFullPath决定显示内容displayValues() {if (this.multiple) {return this.selectedNodes.map(node => this.showFullPath ? this.getNodePath(node) : node[this.VALUE_TEXT])}const firstNode = this.selectedNodes[0]if (!firstNode) return ''return this.showFullPath ? this.getNodePath(firstNode) : firstNode[this.VALUE_TEXT]}},watch: {defaultValue: {handler() {this.$nextTick(() => {// 多选if (this.multiple) {let datalist = this.$refs.treeNode.getCheckedNodes()this.selectTree = datalistthis.selectedNodes = [...datalist]}})},deep: true},// 对树节点进行筛选操作filterText(val) {this.$refs.treeNode.filter(val)}},mounted() {this.$nextTick(() => {const scrollWrap = document.querySelectorAll(".el-scrollbar .el-select-dropdown__wrap")[0];const scrollBar = document.querySelectorAll(".el-scrollbar .el-scrollbar__bar");scrollWrap.style.cssText ="margin: 0px; max-height: none; overflow: hidden;";scrollBar.forEach((ele) => {ele.style.width = 0;});});if (this.multiple) {let datalist = this.$refs.treeNode.getCheckedNodes()this.selectTree = datalistthis.selectedNodes = [...datalist]}// 有defaultData值才回显默认值if (this.defaultData?.id) {this.setDefaultValue(this.defaultData)}},methods: {// 获取节点的完整路径getNodePath(node) {const path = []let currentNode = node// 向上查找父节点,构建路径while (currentNode) {path.unshift(currentNode[this.VALUE_TEXT])currentNode = this.findParentNode(currentNode, this.options)}return path.join('-')},// 查找父节点findParentNode(targetNode, nodes, parent = null) {for (let node of nodes) {if (node[this.VALUE_NAME] === targetNode[this.VALUE_NAME]) {return parent}if (node.children && node.children.length > 0) {const found = this.findParentNode(targetNode, node.children, node)if (found !== null) {return found}}}return null},// 单选设置默认值setDefaultValue(obj) {if (obj.label !== '' && obj.id !== '') {this.selectTree = obj.idthis.selectedNodes = [{ [this.VALUE_NAME]: obj.id, [this.VALUE_TEXT]: obj.label }]this.$nextTick(() => {this.currentKey = this.selectTreethis.setTreeChecked(this.selectTree)})}},// 全选handlecheckAll() {setTimeout(() => {this.$refs.treeNode.setCheckedNodes(this.options)}, 200)},// 清空handleReset() {setTimeout(() => {this.$refs.treeNode.setCheckedNodes([])}, 200)},/*** @description: 反选处理方法* @param {*} nodes 整个tree的数据* @param {*} refs this.$refs.treeNode* @param {*} flag 选中状态* @param {*} seleteds 当前选中的节点* @return {*}*/batchSelect(nodes, refs, flag, seleteds) {if (Array.isArray(nodes)) {nodes.forEach(element => {refs.setChecked(element, flag, true)})}if (Array.isArray(seleteds)) {seleteds.forEach(node => {refs.setChecked(node, !flag, true)})}},// 反选handleReverseCheck() {setTimeout(() => {let res = this.$refs.treeNodelet nodes = res.getCheckedNodes(true, true)this.batchSelect(this.options, res, true, nodes)}, 200)},// 输入框关键字dataFilter(val) {setTimeout(() => {this.filterText = val}, 100)},/*** @description: tree搜索过滤* @param {*} value 搜索的关键字* @param {*} data 筛选到的节点* @return {*}*/filterNode(value, data) {if (!value) return truereturn data[this.treeProps.label].toLowerCase().indexOf(value.toLowerCase()) !== -1},/*** @description: 勾选树形选项* @param {*} data 该节点所对应的对象* @param {*} self 节点本身是否被选中* @param {*} child 节点的子树中是否有被选中的节点* @return {*}*/// 多选赋值组件handleNodeChange(data, self, child) {let datalist = this.$refs.treeNode.getCheckedNodes()this.$nextTick(() => {this.selectTree = datalistthis.selectedNodes = [...datalist]this.$emit('handleNodeClick', this.selectTree)})},// 单选tree点击赋值handleTreeClick(data, node) {if (this.multiple) {} else {this.filterText = ''this.selectTree = data[this.VALUE_NAME]this.selectedNodes = [data]this.currentKey = this.selectTreethis.highlightNode = data[this.VALUE_NAME]this.$emit('handleNodeClick', { id: this.selectTree, label: data[this.VALUE_TEXT] }, node)this.setTreeChecked(this.highlightNode)this.$refs.select.blur()}},setTreeChecked(highlightNode) {if (this.treeAttrs.hasOwnProperty('show-checkbox')) {// 通过 keys 设置目前勾选的节点,使用此方法必须设置 node-key 属性this.$refs.treeNode.setCheckedKeys([highlightNode])} else {// 通过 key 设置某个节点的当前选中状态,使用此方法必须设置 node-key 属性this.$refs.treeNode.setCurrentKey(highlightNode)}},// 移除单个标签removeTag(displayText) {let nodeIndex = -1if (this.showFullPath) {// 完整路径模式:根据完整路径精确匹配nodeIndex = this.selectedNodes.findIndex(node => this.getNodePath(node) === displayText)} else {// 普通模式:根据文本匹配,删除最后一个匹配项nodeIndex = this.selectedNodes.map(node => node[this.VALUE_TEXT]).lastIndexOf(displayText)}if (nodeIndex !== -1) {const nodeToRemove = this.selectedNodes[nodeIndex]// 从selectedNodes中移除this.selectedNodes.splice(nodeIndex, 1)// 从selectTree中移除对应的节点const treeNodeIndex = this.selectTree.findIndex(v => v[this.VALUE_NAME] === nodeToRemove[this.VALUE_NAME])if (treeNodeIndex !== -1) {this.selectTree.splice(treeNodeIndex, 1)}// 更新树的选中状态this.$nextTick(() => {this.$refs.treeNode.setCheckedNodes(this.selectTree)})this.$emit('handleNodeClick', this.selectTree)}},// 文本框清空clearAll() {this.selectTree = this.multiple ? [] : ''this.selectedNodes = []this.$refs.treeNode.setCheckedNodes([])this.$emit('handleNodeClick', this.selectTree)}}}
</script><style scoped lang="scss">
.t-tree-select {.check-box {padding: 0 20px;}.option-style {height: 100%;max-height: 300px;margin: 0;overflow-y: auto;cursor: default !important;}.tree-style {::v-deep .el-tree-node.is-current > .el-tree-node__content {color: #3370ff;}}.el-select-dropdown__item.selected {font-weight: 500;}.el-input__inner {height: 36px;line-height: 36px;}.el-input__icon {line-height: 36px;}.el-tree-node__content {height: 32px;}}
</style>
<style lang="scss" scoped>
::v-deep .el-tree{background: #262F40 !important;color: #FFFFFF;
}
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {height: auto;max-height: 300px;padding: 0;overflow: hidden;overflow-y: auto;
}.el-select-dropdown__item.selected {font-weight: normal;
}ul li >>> .el-tree .el-tree-node__content {height: auto;padding: 0 20px;
}.el-tree-node__label {font-weight: normal;
}.el-tree >>> .is-current .el-tree-node__label {// color: #409eff;font-weight: 700;
}.el-tree >>> .is-current .el-tree-node__children .el-tree-node__label {// color: #606266;font-weight: normal;
}::v-deep .el-tree-node__content:hover,
::v-deep .el-tree-node__content:active,
::v-deep .is-current > div:first-child,
::v-deep .el-tree-node__content:focus {background-color: rgba(#333F52, 0.5);color: #409eff;
}
::v-deep .el-tree-node__content:hover {background-color: rgba(#333F52, 0.5);color: #409eff;
}::v-deep .el-tree-node:focus>.el-tree-node__content{background-color: rgba(#333F52, 0.5);}
.el-popper {z-index: 9999;
}.el-select-dropdown__item::-webkit-scrollbar {display: none !important;
}.el-select {::v-deep.el-tag__close {// display: none !important; //隐藏在下拉框多选时单个删除的按钮}
}
</style><style lang="scss" >
.select-tree {.el-tag.el-tag--info{color: #fff;border-color:none;background: #273142 !important;}.el-icon-close:before{color: rgba(245, 63, 63, 1); }.el-tag__close.el-icon-close{background-color: transparent !important;}
}
</style>
相关文章:

vue2 , el-select 多选树结构,可重名
人家antd都支持,elementplus 也支持,vue2的没有,很烦。 网上其实可以搜到各种的,不过大部分不支持重名,在删除的时候可能会删错,比如树结构1F的1楼啊,2F的1楼啊这种同时勾选的情况。。 可以全…...

Excel处理控件Aspose.Cells教程:使用 C# 从 Excel 进行邮件合并
邮件合并功能让您能够轻松批量创建个性化文档,例如信函、电子邮件、发票或证书。您可以从模板入手,并使用电子表格中的数据进行填充。Excel 文件中的每一行都会生成一个新文档,并在正确的位置包含正确的详细信息。这是一种自动化重复性任务&a…...
Jenkins | Jenkins构建成功服务进程关闭问题
Jenkins构建成功服务进程关闭问题 1. 原因2. 解决 1. 原因 Jenkins 默认会在构建结束时终止所有由构建任务启动的子进程,即使使用了nohup或后台运行符号&。 2. 解决 在启动脚本中加上 BULID_IDdontkillme #--------------解决jenkins 自动关闭进程问题-----…...
模块化架构下的前端调试体系建设:WebDebugX 与多工具协同的工程实践
随着前端工程化的发展,越来越多的项目采用模块化架构:单页面应用(SPA)、微前端、组件化框架等。这类架构带来了良好的可维护性和复用性,但也带来了新的调试挑战。 本文结合我们在多个模块化项目中的真实经验ÿ…...

EXCEL通过DAX Studio获取端口号连接PowerBI
EXCEL通过DAX Studio获取端口号连接PowerBI 昨天我分享了EXCEL链接模板是通过获取端口号和数据库来连接PowerBI模型的,链接:浅析EXCEL自动连接PowerBI的模板,而DAX Studio可以获取处于打开状态的PowerBI的端口号。 以一个案例分享如何EXCEL…...
PostgreSQL 技术峰会,为您打造深度交流优质平台
峰会背景 PostgreSQL 作为全球领先的开源关系型数据库管理系统,凭借其强大的功能、高度的扩展性和稳定性,在云计算、大数据、人工智能等领域得到了广泛应用。随着数字化转型的加速,企业对数据库技术的需求日益复杂和多样化,Postg…...
使用 OpenCV (C++) 进行人脸边缘提取
使用 OpenCV (C) 进行人脸边缘提取 本文将介绍如何使用 C 和 OpenCV 库来检测图像中的人脸,并提取这些区域的边缘。我们将首先使用 Haar级联分类器进行人脸检测,然后在检测到的人脸区域(ROI - Region of Interest)内应用 Canny 边…...

C# 委托UI控件更新例子,何时需要使用委托
1. 例子1 private void UdpRxCallBackFunc(UdpDataStruct info) {// 1. 前置检查防止无效调用if (textBoxOutput2.IsDisposed || !textBoxOutput2.IsHandleCreated)return;// 2. 使用正确的委托类型Invoke(new Action(() >{// 3. 双重检查确保安全if (textBoxOutput2.IsDis…...

大模型数据流处理实战:Vue+NDJSON的Markdown安全渲染架构
在Vue中使用HTTP流接收大模型NDJSON数据并安全渲染 在构建现代Web应用时,处理大模型返回的流式数据并安全地渲染到页面是一个常见需求。本文将介绍如何在Vue应用中通过普通HTTP流接收NDJSON格式的大模型响应,使用marked、highlight.js和DOMPurify等库进…...
python项目如何创建docker环境
这里写自定义目录标题 python项目创建docker环境docker配置国内镜像源构建一个Docker 镜像验证镜像合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPant…...
Eureka 高可用集群搭建实战:服务注册与发现的底层原理与避坑指南
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

PyTorch--池化层(4)
池化层(Pooling Layer) 用于降低特征图的空间维度,减少计算量和参数数量,同时保留最重要的特征信息。 池化作用:比如1080p视频——720p 池化层的步长默认是卷积核的大小 ceil 允许有出界部分;floor 不允许…...
GPU加速与非加速的深度学习张量计算对比Demo,使用PyTorch展示关键差异
import torch import time # 创建大型随机张量 (10000x10000) tensor_size 10000 x_cpu torch.randn(tensor_size, tensor_size) x_gpu x_cpu.cuda() # 转移到GPU # CPU矩阵乘法 start time.time() result_cpu torch.mm(x_cpu, x_cpu.t()) cpu_time time.time() - sta…...
Vue中的自定义事件
一、前言 在 Vue 的组件化开发中,组件之间的数据通信是构建复杂应用的关键。而其中最常见、最推荐的方式之一就是通过 自定义事件(Custom Events) 来实现父子组件之间的交互。 本文将带你深入了解: Vue 中事件的基本概念如何在…...

2025年大模型平台落地实践研究报告|附75页PDF文件下载
本报告旨在为各行业企业在建设落地大模型平台的过程中,提供有效的参考和指引,助力大模型更高效更有价值地规模化落地。本报告系统性梳理了大模型平台的发展背景、历程和现状,结合大模型平台的特点提出了具体的落地策略与路径,同时…...

PPTAGENT:让PPT生成更智能
想要掌握如何将大模型的力量发挥到极致吗?叶梓老师带您深入了解 Llama Factory —— 一款革命性的大模型微调工具。 1小时实战课程,您将学习到如何轻松上手并有效利用 Llama Factory 来微调您的模型,以发挥其最大潜力。 CSDN教学平台录播地址…...
Kotlin 中 companion object 扩展函数和普通函数区别
在 Kotlin 中,companion object 的扩展函数与普通函数(包括普通成员函数和普通扩展函数)有显著区别。以下是它们的核心差异和适用场景: 1. 定义位置与归属 特性companion object 扩展函数普通函数定义位置在类外部为伴生对象添加…...

《汇编语言》第13章 int指令
中断信息可以来自 CPU 的内部和外部,当 CPU 的内部有需要处理的事情发生的时候,将产生需要马上处理的中断信息,引发中断过程。在第12章中,我们讲解了中断过程和两种内中断的处理。 这一章中,我们讲解另一种重要的内中断…...

Redis实战-基于redis和lua脚本实现分布式锁以及Redission源码解析【万字长文】
前言: 在上篇博客中,我们探讨了单机模式下如何通过悲观锁(synchronized)实现"一人一单"功能。然而,在分布式系统或集群环境下,单纯依赖JVM级别的锁机制会出现线程并发安全问题,因为这…...
Ubuntu崩溃修复方案
当Ubuntu系统崩溃时,可依据崩溃类型(启动失败、运行时崩溃、完全无响应)选择以下修复方案。以下方法综合了官方推荐和社区实践,按操作风险由低到高排序: 一、恢复模式(Recovery Mode) 适用场景:系统启动卡顿、登录后黑屏、软件包损坏等。 操作步骤: …...

计算机网络 : 应用层自定义协议与序列化
计算机网络 : 应用层自定义协议与序列化 目录 计算机网络 : 应用层自定义协议与序列化引言1. 应用层协议1.1 再谈协议1.2 网络版计算器1.3 序列化与反序列化 2. 重新理解全双工3. socket和协议的封装4. 关于流失数据的处理5. Jsoncpp5.1 特性5.2 安装5.3…...

Python Day42 学习(日志Day9复习)
补充:关于“箱线图”的阅读 以下图为例 浙大疏锦行 箱线图的基本组成 箱体(Box):中间的矩形,表示数据的中间50%(从下四分位数Q1到上四分位数Q3)。中位线(Median)&#…...

CMake在VS中使用远程调试
选中CMakeLists.txt, 右键-添加调试配置-选中"C\C远程windows调试" 之后将 aunch.vs.json文件改为如下所示: CMake在VS中使用远程调试时,Launch.vs.json中远程调试设置 ,远程电脑开启VS专用的RemoteDebugger {"version": "0.2.1","defaul…...

《图解技术体系》How Redis Architecture Evolves?
Redis架构的演进经历了多个关键阶段,从最初的内存数据库发展为支持分布式、多模型和持久化的高性能系统。以下为具体演进路径: 单线程模型与基础数据结构 Redis最初采用单线程架构,利用高效的I/O多路复用(如epoll)处…...
从零搭建到 App Store 上架:跨平台开发者使用 Appuploader与其他工具的实战经验
对于很多独立开发者或小型团队来说,开发一个 iOS 应用并不难,真正的挑战在于最后一步:将应用成功上架到 App Store。尤其是当你主要在 Windows 或 Linux 系统上开发,缺乏苹果设备和 macOS 环境时,上架流程往往变得繁琐…...
Spring Cloud 2025 正式发布啦
文章目录 一、版本兼容性二、Spring Cloud Gateway 重大更新1、新增功能1.1 Function & Stream 处理器集成1.2 Bucket4j 限流器支持 2、重要弃用2.1. WebClientRouting 基础设施2.2. 模块和启动器重命名 3、破坏性变更3.1 X-Forwarded-* 头部默认禁用3.2 配置受信任代理:3.…...

一文速通Python并行计算:12 Python多进程编程-进程池Pool
一文速通 Python 并行计算:12 Python 多进程编程-进程池 Pool 摘要: 在Python多进程编程中,Pool类用于创建进程池,可并行执行多个任务。通过map、apply等方法,将函数和参数分发到子进程,提高CPU利用率&…...
相机Camera日志分析之二十五:高通相机Camx 基于预览1帧的process_capture_request四级日志分析详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:相机Camera日志分析之二十四:高通相机Camx 基于预览1帧的process_capture_request三级日志分析详解 ok 这一篇我们开始讲: 相机Camera日志分析之二十五:高通相机Camx 基于预览1帧的process_capture_…...
React从基础入门到高级实战:React 实战项目 - 项目一:在线待办事项应用
React 实战项目:在线待办事项应用 欢迎来到本 React 开发教程专栏的第 26 篇!在之前的 25 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件、状态、路由和性能优化等核心知识。这一次,我们将通过一个…...
云部署实战:基于AWS EC2/Aliyun ECS与GitHub Actions的CI/CD全流程指南
在当今快速迭代的软件开发环境中,云部署与持续集成/持续交付(CI/CD)已成为现代开发团队的标配。本文将详细介绍如何利用AWS EC2或阿里云ECS结合GitHub Actions构建高效的CI/CD流水线,从零开始实现自动化部署的全过程。 最近挖到一个宝藏级人工智能学习网…...