【vue】封装树形下拉框组件 el-popover+el-tree+el-select

父组件使用
<template><div>{{ array }}  更多属性详见wgyTreeSelect组件<wgyTreeSelectv-model="array":list="list":multiple="true":disabled-ids="[111,113,2]"/></div>
</template><script>
/* 注意: 默认是这种结构id: 'id', // IDlabel: 'name', // 显示名称children: 'children', // 子级字段名path: 'path', // 路径content: 'content', // 描述pid: 'pid', // 父id如果不是这种结构传入obj定义
*/
export default {data() {return {array: [],//数据源list: [{id: '1', // IDname: '上海市', // 显示名称children: [{id: '2', // IDname: '嘉定区', // 显示名称children: [{id: '3', // IDname: '江桥镇11111111111111111111111111111', // 显示名称content: '嘉定', // 描述pid: '2', // 父id},{id: '4', // IDname: '安亭镇', // 显示名称content: '安亭', // 描述pid: '2', // 父id},], // 子级字段名content: '嘉定', // 描述pid: '1', // 父id},{id: '2000000', // IDname: '嘉定2区', // 显示名称children: [{id: '3876543', // IDname: '江桥2镇11111111111111111111111111111', // 显示名称content: '嘉定', // 描述pid: '2000000', // 父id},], // 子级字段名content: '嘉定', // 描述pid: '1', // 父id},], // 子级字段名content: '上海魔都', // 描述pid: '0', // 父id},{id: '11', // IDname: '北京市', // 显示名称children: [{id: '12', // IDname: '朝阳区', // 显示名称children: [{id: '13', // IDname: '三里屯', // 显示名称content: '三里屯', // 描述pid: '12', // 父id},{id: '111', // IDname: '四里屯--------------', // 显示名称pid: '12', // 父id},{id: '113', // IDname: '五里屯--------------', // 显示名称pid: '12', // 父id},{id: '123', // IDname: '六里屯--------------', // 显示名称pid: '12', // 父id},{id: '11111', // IDname: '七里屯--------------', // 显示名称pid: '12', // 父id},{id: '11311', // IDname: '八里屯--------------', // 显示名称pid: '12', // 父id},{id: '12312', // IDname: '九里屯--------------', // 显示名称pid: '12', // 父id},{id: '11113331', // IDname: '十里屯--------------', // 显示名称pid: '12', // 父id},{id: '11344411', // IDname: '十一里屯--------------', // 显示名称pid: '12', // 父id},{id: '12555312', // IDname: '十二里屯--------------', // 显示名称pid: '12', // 父id},{id: '14', // IDname: '左家庄--------------', // 显示名称content: '左家庄', // 描述pid: '12', // 父id},], // 子级字段名content: '朝阳', // 描述pid: '11', // 父id},], // 子级字段名content: '北京', // 描述pid: '0', // 父id},],};},
}
</script> 
子组件
<template><div><el-popoverv-model="isShowSelect"placement="bottom-start":width="popoverWidth":close-on-click-modal="false"trigger="manual"@hide="popoverHide"><el-treeref="tree"v-bind="$attrs"class="common-tree":width="width":data="treeData":props="obj":show-checkbox="multiple":node-key="obj.id":check-strictly="checkStrictly":default-expanded-keys="defaultKeys":expand-on-click-node="multiple&&expandClickNode":check-on-click-node="checkClickNode":highlight-current="true"@check-change="nodeClick"@node-click="nodeClick"/><el-selectslot="reference"ref="select"v-bind="$attrs"v-model="returnDataKeys":size="size":width="width":multiple="multiple":clearable="clearable":collapse-tags="collapseTags"class="tree-select"@click.native="selectClick"@remove-tag="removeTag"@clear="clear"@mouseenter.native="showCloseIcon = true"@mouseleave.native="showCloseIcon = false"><el-optionv-for="item in options":key="item.value":label="item.label":value="item.value"/><!-- 这里是删除整个下拉框的内容,多选的时候,是没有这个功能的,所有自己弄了一个icon --><templateslot="prefix"><iv-if="multiple && clearable && returnDataKeys.length && showCloseIcon"class="el-icon-close"@click.stop="clearSelectedNodes"></i><i></i></template></el-select></el-popover></div>
</template><script>
export default {name: 'TreeSelect',props: {// 绑定的值value: {tyep: Object,},// 树结构数据list: {type: Array,default: () => ([]),},obj: {type: Object,required: false,default: () => ({id: 'id', // IDlabel: 'name', // 显示名称children: 'children', // 子级字段名path: 'path', // 路径content: 'content', // 描述pid: 'pid', // 父id}),},// 配置是否可多选multiple: {type: Boolean,default: false,},// 配置是否可清空选择,只对单选时生效, 多选时自定义清空按钮clearable: {type: Boolean,default: true,},// 配置多选时是否将选中值按文字的形式展示collapseTags: {type: Boolean,default: false,},// 显示复选框情况下,是否严格遵循父子不互相关联checkStrictly: {type: Boolean,default: false,},// 多选时设置点击节点是否可以选中,false是只有点击多选框才选中,点击元素不选中checkClickNode: {type: Boolean,default: false,},// 多选时:点击节点展开还是点三角标,true是点击节点展开,false是点击三角形展开expandClickNode: {type: Boolean,default: false,},size: {type: String,default: 'small',},width: {type: String,default: '200px',},// 父节点全选时, 是否只展示子节点onlyLeaf: {type: Boolean,default: false,},// 父节点全选时,是否只展示父节点mergeTag: {type: Boolean,default: false,},// 外部点击是否收起树形, 默认收起closeOnOutsideClick: {type: Boolean,default: true,},// 禁止选中的数据disabledIds: {type: Array,default: () => ([]),},},// 上面是父组件可传入参数data() {return {defaultKeys: [], // 默认展开的节点defaultKey: '',first: false, //popoverWidth: '0px', // 下拉框大小isShowSelect: false, // 是否显示树状选择器options: [], // select option选项returnDatas: [], // 返回给父组件数组对象returnDataKeys: [], // 返回父组件数组主键值showCloseIcon: false, // 清空icon};},computed: {treeData() {// 判断传入的数据是不是树形结构const isTreeStructure = JSON.stringify(this.list).indexOf(this.obj.children) !== -1;// 是树形结构,就返回传入的数据, 不是的话格式化成树形结构return isTreeStructure ? this.list : this.toTreeStructure(this.list);},},watch: {// 是否显示树状选择器isShowSelect() {// 隐藏select自带的下拉框this.$refs.select.blur();},// 监听tree数据treeData() {this.$nextTick(() => {this.init();});},// 监听value从新赋值value: {handler(val) {this.$nextTick(() => {if (this.multiple) {this.defaultKeys = val;} else {this.defaultKey = val;}this.init();});},immediate: true,},// 监听选中的值returnDataKeys: {handler(val) {if (this.first || val) {this.first = true;this.$emit('input', val);} else {this.first = true;}},},// 监听禁用数组disabledIds: {handler(val) {console.log(val);this.addDisabledProperty(this.list, val);},},},mounted() {if (this.closeOnOutsideClick) {document.addEventListener('click', this.handleClickOutside);}},beforeDestroy() {if (this.closeOnOutsideClick) {document.removeEventListener('click', this.handleClickOutside);}},methods: {// 传入数据类型不是树形结构,转成树形结构toTreeStructure(list) {console.log(list);const map = {}; let node; const roots = []; leti;for (i = 0; i < list.length; i += 1) {map[list[i].id] = i; // 初始化maplist[i].children = []; // 初始化children}for (i = 0; i < list.length; i += 1) {node = list[i];if (node.pid !== '0') {// 如果有父级list[map[node.pid]].children.push(node);} else {// 如果没有父级,则为根节点roots.push(node);}}return roots;},// 点击其他元素, 树隐藏handleClickOutside(event) {if (!this.$refs.select?.$el?.contains(event.target)) {this.isShowSelect = false;}},init() {//  如果是多选,if (this.multiple) {// 且默认展开的节点大于0if (Array.isArray(this.defaultKeys) && this.defaultKeys.length > 0) {// 检测this.defaultKeys[0]是否是一个对象。if (Object.prototype.toString.call(this.defaultKeys[0]).indexOf('Object') !== -1) { // 对象this.setDatas(this.defaultKeys);// 检测this.defaultKeys[0]是否是一个数字或者字符串。} else if (Object.prototype.toString.call(this.defaultKeys[0]).indexOf('Number') !== -1|| Object.prototype.toString.call(this.defaultKeys[0]).indexOf('String') !== -1) {this.setKeys(this.defaultKeys);} else {console.log('多选:传入参数类型不匹配');}}} else {// 单选if (Object.prototype.toString.call(this.defaultKey).indexOf('Number') !== -1|| Object.prototype.toString.call(this.defaultKey).indexOf('String') !== -1|| Object.prototype.toString.call(this.defaultKey).indexOf('Object') !== -1) {this.setKey(this.defaultKey);} else {console.log('单选:传入参数类型不匹配');}}},// 下拉框select点击[入口]selectClick() {this.isShowSelect = !this.isShowSelect;},// 节点被点击  nodeClick(a, node) {// 单选if (!this.multiple) {this.isShowSelect = false;this.setKey(node.key);// 多选} else {// 所有被选中的节点的 key 所组成的数组数据const checkedKeys = this.$refs.tree.getCheckedKeys();let selectedNodes = checkedKeys.map((item) => {// 所有被选中的节点对应的nodeconst { data, label, key } = this.$refs.tree.getNode(item);return { label, value: key, data };});// 如果onlyLeaf为true,mergeTag为false只保留叶子节点if (this.onlyLeaf && !this.mergeTag) {selectedNodes = selectedNodes.filter((n) => !n.data.children);}// 如果mergeTag为true,onlyLeaf为false只保留父节点if (this.mergeTag && !this.onlyLeaf) {selectedNodes = selectedNodes.filter((n) => {// 判断当前节点是否有父节点if (n.data.pid) {// 判断当前节点的父节点是否也在selectedNodes中const parentInSelectedNodes = selectedNodes.some((upN) => upN.data.id === n.data.pid);// 如果父节点也在selectedNodes中,就将当前节点从selectedNodes中移除return !parentInSelectedNodes;}return true;});}// 设置option选项this.options = selectedNodes;this.returnDataKeys = selectedNodes.map((item) => item.value);this.returnDatas = selectedNodes.map((n) => n.data);}},// 单选:清空选中clear() {this.$refs.tree.setCurrentKey(null);// 清除树选中keythis.returnDatas = null;this.returnDataKeys = '';this.popoverHide();this.isShowSelect = false;},// 单选:设置、初始化值 keysetKey(thisKey) {if (thisKey) {// 设置当前选中的值, 获取当前值对应的节点, 设置当前节点this.$refs.tree.setCurrentKey(thisKey);const node = this.$refs.tree.getNode(thisKey);this.setData(node.data);}},// 单选:设置、初始化对象setData(data) {this.options = [];this.options.push({ label: data[this.obj.label], value: data[this.obj.id] });this.returnDatas = data;this.returnDataKeys = data[this.obj.id];},// 多选:设置、初始化值 keyssetKeys(checkedKeys) {// 给树状选择器设置选中的节点。 给select赋值this.$refs.tree.setCheckedKeys(checkedKeys);this.returnDataKeys = checkedKeys;const selectedNodes = checkedKeys.map((item) => {// 所有被选中的节点对应的nodeconst node = this.$refs.tree.getNode(item);return { label: node.label, value: node.key, data: node.data };});this.returnDatas = selectedNodes.map((node) => node.data);this.popoverHide();},// 多选:设置、初始化对象  setDatas(data) {// 获取选中节点的主键值const checkedKeys = data.map((item) => item[this.obj.id]);// 设置树状选择器的选中节点this.$refs.tree.setCheckedKeys(checkedKeys);// 设置返回给父组件的数组对象this.returnDatas = data;this.returnDataKeys = checkedKeys;this.popoverHide();},// 多选模式下,当删除选中的节点时,将该节点及其子节点设置为未选中状态,并更新选中的节点。 okremoveTag(val) {// 获取删除的节点const node = this.$refs.tree.getNode(val);// 判断获取的节点是否为叶子节点const isLeafNode = node.childNodes.length === 0;// 是叶子节点,那么只需要将该节点设置为未选中状态// 不是叶子节点,那么需要将该节点及其所有子节点设置为未选中状态const nodesToUncheck = isLeafNode ? [node] : this.treeToList(node);// 将每个节点设置为未选中状态。nodesToUncheck.forEach((n) => this.$refs.tree.setChecked(n, false));// 更新选中的节点。this.nodeClick();this.popoverHide();},// 下拉框关闭执行popoverHide() {this.$emit('getValue', this.returnDataKeys, this.returnDatas);},// 多选,清空所有被选中的节点clearSelectedNodes() {this.$refs.tree.setCheckedKeys([]);},// 树形转为集合treeToList(tree) {let queen = [];const out = [];queen = queen.concat(tree);while (queen.length) {const first = queen.shift();if (first.childNodes) {queen = queen.concat(first.childNodes);}out.push(first);}return out;},// 禁用某个节点addDisabledProperty(data, ids) {data.forEach((item) => {if (ids.includes(+item.id)) {item.disabled = true;}if (item.children) {this.addDisabledProperty(item.children, ids);}});},},
};
</script><style scoped lang="scss">
::v-deep .el-input__prefix{position: absolute;height: 100%;right: 5px;.el-icon-close {position: absolute;right: 6px;top: 11px;z-index: 1;border-radius:50%;color: #fff;background-color: #B0B3B8;}
}.mask{height: 100%;position: fixed;top: 0;left: 0;opacity: 0;z-index: 11;}.common-tree{overflow: auto;}.tree-select{position: relative;z-index: 111;}.ok{float: right;}.el-row{padding-top: 0px !important;}
</style>
 
相关文章:
【vue】封装树形下拉框组件 el-popover+el-tree+el-select
父组件使用 <template><div>{{ array }} 更多属性详见wgyTreeSelect组件<wgyTreeSelectv-model"array":list"list":multiple"true":disabled-ids"[111,113,2]"/></div> </template><script> /*…...
docker安装Kafka,SpringBoot整合Kafka
#拉取镜像 docker pull wurstmeister/zookeeper #运行容器 docker run --restartalways --name zookeeper -p 2181:2181 \ -v /etc/localtime:/etc/localtime -d wurstmeister/zookeeper#拉取镜像 docker pull wurstmeister/kafka#运行容器 docker run --restartalways --name …...
MySQL - InnoDB 的事务支持、锁机制
InnoDB 存储引擎实现了强大的事务支持和锁机制: 事务原理: ACID 属性:InnoDB 支持 ACID(原子性、一致性、隔离性、持久性)属性,确保数据的一致性和可靠性。事务是一组 SQL 操作,要么全部执行&…...
Android Studio的笔记--Module新建和使用
Module新建和使用 新建module使用module android studio 中module的建立和使用。比如修改工程为module的步骤,引用module的步骤。 新建module 1、新建android工程,New Project.包名为com.lxh.serialport 2、修改工程为module。 2.1、在app下的build.pro…...
Git统计个人提交代码行数
目录 一、git bash打开二、查看个人提交的代码行数统计三、查看项目每个人提交的代码行数统计四、查询所有用户的提交总次数五、统计用户一段时间内的提交代码量 在实际开发中,常常会想查看自己对于某个项目的贡献,管理者会查看项目下各成员的贡献&#…...
Collction的List方法,list特有方法,遍历方式,迭代器选择
[to] list特有方法 //插入指定元素//list.add(1,"ddd");//System.out.println(list);//[aaa, ddd, bbb, ccc]//这个表示在一索引的位置插入ddd//他会把原来一索引位置的元素往后移动一位在添加//删除指定元素//String remove list.remove(1);//System.out.println(…...
奇偶校验码和循环冗余码
在数据链路层的传输中,1可能变成0,0可能变成1,这是比特差错。 为了应对比特差错,有两种方式,即自动重传请求ARQ(Automatic Repeat-reQuest)和前向纠错FEC(Forward Error Correction&…...
Recommender System复习(考试向)
Recommender System Review OverviewCollaborative Filtering基于用户的CF(User CF)基于物品的CF(Item CF)Similarity CalculationBias in CF Evaluation of Recommender SystemFactorization MachinesLatent factor modelLFM算法…...
SpringBoot绑定配置文件中变量的四种方式-解析
当在Spring Boot中需要绑定配置文件中的变量时,可以使用以下注解: PropertySource:用于指定要加载的属性文件。可以将该注解放置在Configuration类上。 Configuration PropertySource("classpath:application.properties") public…...
linux 安装 elasticsearch 全教程
一、去 elasticsearch官网找到Linux版本的下载链接 地址https://www.elastic.co/cn/downloads/elasticsearch 二、在linux 中用wget下载 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.10.4-linux-x86_64.tar.gz三、下载成功后解压文件 tar -x…...
更快更准 | YOLOv3算法超详细解析(包括诞生背景+论文解析+技术原理等)
前言:Hello大家好,我是小哥谈。YOLOv3是一种基于深度学习的目标检测算法,它可以快速而准确地在图像中检测出多个目标。它是由Joseph Redmon和Ali Farhadi在2018年提出的,是YOLO(You Only Look Once)系列算法…...
【ChatGPT】教我 Flyweight(享元) 模式
文章目录 设计模式中 Flyweight 模式,实际应用场景有哪些?我需要画很多的树,以这个需求为例来教我 Flyweight 模式。好的,我大概明白了,我还有点疑惑,请问外在状态和内在状态是哪些?你可以讲一下…...
双十一越来越早,公域电商何去何从——深度解析
为什么双十一越来越早?传统的公域电商越来越饱和,某淘某东甚至和某79元网红打起了价格战 ,市面上标品越来越多,商家越来越多,买东西的变少了,商家越卖越便宜。 公域电商: 就像一个大市场。里面摆满了各种商…...
区块链中的 “不可能三角,技术性ppt突出关键技术点,数据交易-安全问题
目录 区块链中的 "不可能三角 技术性ppt突出关键技术点 数据交易-安全问题...
[Docker]五.Docker中Dockerfile详解
Dockerfile 就是用来构建 docker 镜像的构建文件 1.Dockerfile 构建一个自己的 centos 镜像 新建一个名为 Dockerfile 文件,并在文件内添加以下内容: #基于centos构建镜像 FROM centos #安装net-tools软件: RUN表示安装软件 RUN yum install -y net-tools…...
react使用react-sortable-hoc实现拖拽
react-sortable-hoc拖拽 安装 npm install react-sortable-hoc --save 代码如下(示例): import React, { useImperativeHandle, forwardRef, memo, useState } from react;import { DrawerForm } from ant-design/pro-form;import { messag…...
实习日常的点点滴滴记录(Spring Boot的核心注解)------慢慢积累,厚积薄发(要学的东西还好多,加油!))(知识和实践的结合)
Spring Boot的核心注解有: **SpringBootApplication:**这是Spring Boot最核心的注解,用于开启Spring Boot的各项能力。 它其实是SpringBootConfiguration、EnableAutoConfiguration、ComponentScan这三个注解的组合。 Configuration…...
第 04 章_逻辑架构
第 04 章_逻辑架构 1. 逻辑架构剖析 1. 1 服务器处理客户端请求 那服务器进程对客户端进程发送的请求做了什么处理,才能产生最后的处理结果呢?这里以查询请求为 例展示: 下面具体展开看一下: 1.2 Connectors 1.3 第 1 层&…...
免费API接口资源推荐
企业基本信息(含联系方式):通过公司名称/公司ID/注册号或社会统一信用代码获取企业基本信息和企业联系方式,包括公司名称或ID、类型、成立日期、电话、邮箱、网址等字段的详细信息。企业投资:获取企业对外投资信息,对外投资信息包…...
LuatOS-SOC接口文档(air780E)--miniz - 简易zlib压缩
示例 -- 准备好数据 local bigdata "123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw" -- 压缩之, 压缩得到的数据是zlib兼容的,其他语言可通过zlib相关的库进行解压 local cdata miniz.compress(bigdata) -- lua 的 字符串相当于有长度的cha…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
深入解析 ReentrantLock:原理、公平锁与非公平锁的较量
ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...
