【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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/181544.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于 golang 从零到一实现时间轮算法 (二)

Go实现单机版时间轮 上一章介绍了时间轮的相关概念&#xff0c;接下来我们会使用 golang 标准库的定时器工具 time ticker 结合环状数组的设计思路&#xff0c;实现一个单机版的单级时间轮。 首先我们先运行一下下面的源码&#xff0c;看一下如何使用。 https://github.com/x…

2023辽宁省数学建模B题数据驱动的水下导航适配区分类预测完整原创论文分享(python求解)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了辽宁省数学建模B题完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。 B用Python&#xff0b;SPSSPRO求解&…

Tomcat运行日志乱码问题/项目用tomcat启动时窗口日志乱码

文章目录 一、问题描述&#xff1a;二、产生原因三、解决方法 一、问题描述&#xff1a; 项目在idea中运行时日志是正常的&#xff0c;用Tomcat启动时发现一大堆看不懂的文字&#xff0c;如 二、产生原因 产生乱码的根本原因就是编码和解码不一致&#xff0c;举个例子就是翻…

Adobe:受益于人工智能,必被人工智能反噬

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;Adobe(ADBE)受益于生成式人工智能的兴起&#xff0c;其一直能实现两位数的收入增长就证明了这一点。 &#xff08;2&#xff09;在生成式人工智能兴起时&#xff0c;该公司就快…

STM32-高级定时器

以STM32F407为例。 高级定时器 高级定时器比通用定时器增加了可编程死区互补输出、重复计数器、带刹车&#xff08;断路&#xff09;功能&#xff0c;这些功能都是针对工业电机控制方面。 功能框图 16位向上、向下、向上/向下自动重装载计数器。 16位可编程预分频器&#xff0c…

小程序https证书

小程序通常需要与服务器进行数据交换&#xff0c;包括用户登录信息、个人资料、支付信息等敏感数据。如果不使用HTTPS&#xff0c;这些数据将以明文的方式在网络上传输&#xff0c;容易被恶意攻击者截获和窃取。HTTPS通过数据加密来解决这个问题&#xff0c;确保数据在传输过程…

Jenkins中解决下载maven包巨慢的问题

背景介绍 我们在使用jenkins构建maven项目时由于依赖很多第三方jar包&#xff0c;默认会从maven中央仓库下载&#xff0c;由于maven中央仓库服务器是国外的&#xff0c;所以下载很慢&#xff0c;甚至会超时 解决办法 增加jenkins maven 源配置 如下图所示&#xff0c;增加m…

默认路由配置

默认路由&#xff1a; 在末节路由器上使用。&#xff08;末节路由器是前往其他网络只有一条路可以走的路由器&#xff09; 默认路由被称为最后的关卡&#xff0c;也就是静态路由不可用并且动态路由也不可用&#xff0c;最后就会选择默认路由。有时在末节路由器上写静态路由时…

[直播自学]-[汇川easy320]搞起来(1)给PLC供电

从没正儿八经的用一用PLC&#xff0c;所以双11在淘宝入手一个EASY320&#xff0c;大概1000出头。 到货后&#xff0c;汇川官网搜了一下资料&#xff0c;搜到这几个&#xff1a; 首先是给PLC供电吧&#xff0c;看了下PLC前面是24V&#xff0c;不知道供电范围多宽&#xff0c;于…

gcc -static 在centos stream8 和centos stream9中运行报错的解决办法

gcc -static 在centos stream8 和centos stream9中运行报错的解决办法&#xff1a; 报/usr/bin/ld: cannot find -lc 我们下载glibc-static&#xff1a; 选择x86_64的。 还有一个是libxcrypt-static&#xff0c;依旧在这个网站里搜。 rpm -ivh glibc-static-2.28-239.el8.x…

基于SSM的模具制造企业订单跟踪管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

如何在知识付费系统小程序开发中实现社区互动和用户参与

在知识付费系统小程序的开发中&#xff0c;实现社区互动和用户参与可以通过以下步骤实现&#xff1a; 1. 建立用户身份验证和管理系统 // 后端示例代码&#xff08;Node.js&#xff09; // 用户注册 app.post(/register, (req, res) > {const { username, email, passwor…

重新思考边缘负载均衡

本文介绍了Netflix在基于轮询的负载均衡的基础上&#xff0c;集成了包括服务器使用率在内的多因素指标&#xff0c;并对冷启动服务器进行了特殊处理&#xff0c;从而优化了负载均衡逻辑&#xff0c;提升了整体业务性能。原文: Rethinking Netflix’s Edge Load Balancing[1] 我…

STM32 IAP应用开发--bootloader升级程序

STM32 IAP应用开发--bootloader升级程序 Chapter1 STM32 IAP应用开发——通过串口/RS485实现固件升级&#xff08;方式2&#xff09;前言什么是IAP&#xff1f;什么是BootLoader&#xff1f; 方案介绍&#xff1a;1&#xff09;bootloader部分&#xff1a;2&#xff09;APP部分…

腾讯云服务器CVM S5服务器CPU性能测评和优惠价格表

腾讯云服务器CVM标准型S5有活动&#xff0c;CVM 2核2G S5优惠价280.8元一年自带1M带宽&#xff0c;15个月313.2元、2核4G配置748.2元15个月、4核8G配置1437.24元15个月、8核16G优惠价3048.48元15个月&#xff0c;公网带宽可选1M、3M、5M或10M&#xff0c;腾讯云服务器网txyfwq.…

cp没有--exclude选项!Linux复制文件夹时如何排除一些文件?

之前使用tar命令压缩文件将时&#xff0c;使用了–exclude选项排除了一些不需要的文件。现在我想复制一个文件夹&#xff0c;但是其中一些文件不需要复制&#xff0c;此时注意到cp命令居然没有–exclude选项。 rsync可以快速地帮助我们完成相同的事情&#xff0c;命令如下&…

在 CelebA 数据集上训练的 PyTorch 中的基本变分自动编码器

摩西西珀博士 一、说明 我最近发现自己需要一种方法将图像编码到潜在嵌入中&#xff0c;调整嵌入&#xff0c;然后生成新图像。有一些强大的方法可以创建嵌入或从嵌入生成。如果你想同时做到这两点&#xff0c;一种自然且相当简单的方法是使用变分自动编码器。 这样的深度网络不…

竞赛 深度学习疫情社交安全距离检测算法 - python opencv cnn

文章目录 0 前言1 课题背景2 实现效果3 相关技术3.1 YOLOV43.2 基于 DeepSort 算法的行人跟踪 4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习疫情社交安全距离检测算法 ** 该项目较为新颖&#xff0c;适合作为竞赛…

数据结构—字符串

文章目录 7.字符串(1).字符串及其ADT#1.基本概念#2.ADT (2).字符串的基本操作#1.求子串substr#2.插入字符串insert#3.其他操作 (3).字符串的模式匹配#1.简单匹配(Brute-Force方法)#2.KMP算法I.kmp_match()II.getNext() #3.还有更多 小结附录&#xff1a;我自己写的string 7.字符…

幂等性(防重复提交)

文章目录 1. 实现原理2.使用示例3. Idempotent注解4. debug过程 主要用途&#xff1a;防止用户快速双击某个按钮&#xff0c;而前端没有禁用&#xff0c;导致发送两次重复请求。 1. 实现原理 幂等性要求参数相同的方法在一定时间内&#xff0c;只能执行一次。本质上是基于red…