通过el-select选择器和el-tree树形结构二次封装(vue2+elementUI),开发element-plus的TreeSelect树形选择器

news2024/12/23 8:55:38

需求:

领导看我在另一个vue3项目的el-tree-select挺好的,叫我移入vue2的项目中。
但是vue2版本的elementUI,并没有这个组件,所以只能自己找,找半天找不到和它差不多的,通过网友写的组件改写的

参考链接:

利用 el-select 和 el-tree 实现树形结构多选框联动功能

组件示例照片:

照片1
照片2

使用:

<elTreeSelect
    :props="{
    value: 'id',
    label: 'label',
    children: 'children',
  }"
    :options="deptOptions"
    :value="deptId"
    :clearable="false"
    :accordion="true"
    @getValue="handleNodeClick"
    height="200"
/>



  data() {
    return {
    	deptId: '', // 牧场id
    	deptOptions: [
        {
            "id": 201,
            "label": "突泉县",
            "children": [
                {
                    "id": 202,
                    "label": "东杜尔基镇",
                    "children": [
                        {
                            "id": 12,
                            "label": "东方镜养殖户",
                            "farmFlag": "1",
                            "level": null
                        }
                    ],
                    "farmFlag": null,
                    "level": "4"
                },
                {
                    "id": 203,
                    "label": "六户镇",
                    "children": [
                        {
                            "id": 14,
                            "label": "澜养殖户",
                            "farmFlag": "1",
                            "level": null
                        }
                    ],
                    "farmFlag": null,
                    "level": "4"
                },
                {
                    "id": 204,
                    "label": "永安镇",
                    "farmFlag": null,
                    "level": "4"
                },
                {
                    "id": 205,
                    "label": "学田乡",
                    "farmFlag": null,
                    "level": "4"
                },
                {
                    "id": 206,
                    "label": "宝石镇",
                    "children": [
                        {
                            "id": 3,
                            "label": "张三养殖户",
                            "farmFlag": "1",
                            "level": null
                        }
                    ],
                    "farmFlag": null,
                    "level": "4"
                },
                {
                    "id": 207,
                    "label": "太平乡",
                    "farmFlag": null,
                    "level": "4"
                },
                {
                    "id": 208,
                    "label": "突泉镇",
                    "farmFlag": null,
                    "level": "4"
                },
                {
                    "id": 209,
                    "label": "水泉镇",
                    "farmFlag": null,
                    "level": "4"
                },
                {
                    "id": 210,
                    "label": "内蒙古自治区国营杜尔基农场",
                    "farmFlag": null,
                    "level": "4"
                },
                {
                    "id": 211,
                    "label": "九龙乡",
                    "farmFlag": null,
                    "level": "4"
                }
            ],
            "farmFlag": null,
            "level": "3"
        }
    ], // tree数据
    },
    methods: {
    	// 节点单击事件
    	handleNodeClick(data) {
    		console.log('选择的数据', data);
   		}
    }

组件代码:

<template>
  <el-select
    v-model="valueTitle"
    :clearable="clearable"
    @clear="clearHandle"
    ref="treeSelect"
    filterable
    :filter-method="filterSelect"
    @visible-change="clearSelect"
    placeholder="请选择"
  >
    <!-- <el-input
      class="selectInput"
      :placeholder="placeholder"
      v-model="filterText"
    >
    </el-input> -->

    <el-option :value="valueTitle" :label="valueTitle" class="options">
      <el-tree
        id="tree-option"
        ref="selectTree"
        :accordion="accordion"
        :data="treeOptions"
        :props="props"
        :node-key="props.value"
        :default-expanded-keys="defaultExpandedKey"
        :filter-node-method="filterNode"
        @node-click="handleNodeClick"
      >
      </el-tree>
    </el-option>
  </el-select>
</template>

<script>
export default {
  name: "el-tree-select",
  props: {
    /* 配置项 */
    props: {
      type: Object,
      default: () => {
        return {
          value: "id", // ID字段名
          label: "title", // 显示名称
          children: "children", // 子级字段名
        };
      },
    },
    /* 选项列表数据(树形结构的对象数组) */
    options: {
      type: Array,
      default: () => {
        return [];
      },
    },
    /* 初始值 */
    value: {
      type: Number | String,
      default: () => {
        return null;
      },
    },
    /* 可清空选项 */
    clearable: {
      type: Boolean,
      default: () => {
        return true;
      },
    },
    /* 自动收起 */
    accordion: {
      type: Boolean,
      default: () => {
        return false;
      },
    },
    placeholder: {
      type: String,
      default: () => {
        return "检索关键字";
      },
    },
  },
  data() {
    return {
      filterText: "",
      valueId: this.value, // 初始值
      valueTitle: "",
      defaultExpandedKey: [],
      treeOptions: [],
    };
  },
  mounted() {
    this.initHandle();
  },
  methods: {
    // 初始化值
    initHandle() {
      if (this.valueId && this.options && this.options.length > 0) {
        let info = this.findFirstDeptFarm2(this.options);
        this.valueTitle = info.label; // 初始化显示
        // this.$refs.selectTree.getNode(this.valueId).data[this.props.label]
        this.$refs.selectTree.setCurrentKey(this.valueId); // 设置默认选中
        this.defaultExpandedKey = [this.valueId]; // 设置默认展开

        this.treeOptions = this.options;
      }
      this.initScroll();
    },
    // 初始化滚动条
    initScroll() {
      this.$nextTick(() => {
        let scrollWrap = document.querySelectorAll(
          ".el-scrollbar .el-select-dropdown__wrap"
        )[0];
        let 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));
      });
    },
    // 切换选项
    handleNodeClick(node) {
      this.valueTitle = node[this.props.label];
      this.valueId = node[this.props.value];
      this.$emit("getValue", {
        id: this.valueId,
        label: this.valueTitle,
        farmFlag: node.farmFlag,
      });
      this.defaultExpandedKey = [];
      // if (!node.children || !node.children.length) {
      //补录选择完选项弹框不能收起
      this.$refs.treeSelect.blur();
      // }
    },
    // 清除选中
    clearHandle() {
      this.valueTitle = "";
      this.valueId = null;
      this.defaultExpandedKey = [];
      this.clearSelected();
      this.$emit("getValue", null);
    },
    /* 清空选中样式 */
    clearSelected() {
      let allNode = document.querySelectorAll("#tree-option .el-tree-node");
      allNode.forEach((element) => element.classList.remove("is-current"));
    },
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },
    findFirstDeptFarm2(arr) {
      for (let i = 0; i < arr.length; i++) {
        if (arr[i].id === this.valueId) {
          return arr[i];
        } else if (
          Array.isArray(arr[i].children) &&
          arr[i].children.length > 0
        ) {
          const result = this.findFirstDeptFarm2(arr[i].children);
          if (result) {
            return result;
          }
        }
      }
      return null;
    },
    clearSelect(show) {
      if (!show) {
        this.treeOptions = this.options;
      }
    },
    filterSelect(val) {
      if (val) {
        this.treeOptions = this.filterTreeByName(this.options, val);
      } else {
        this.treeOptions = this.options;
      }
    },
    filterTreeByName(tree, nameToMatch) {
      // 递归函数,用于遍历树并找到匹配的节点及其父节点
      function traverseAndFilter(node, filteredTree = []) {
        // 如果节点的name匹配,则将其添加到filteredTree中
        if (node.label.indexOf(nameToMatch) !== -1) {
          filteredTree.push(node);
        }

        // 遍历节点的子节点
        if (node.children) {
          for (let child of node.children) {
            // 递归调用traverseAndFilter来检查子节点
            traverseAndFilter(child, filteredTree);
          }
        }

        // 如果filteredTree不为空,说明找到了匹配项,返回filteredTree
        // 否则返回null,表示当前节点及其子节点中都没有匹配项
        return filteredTree.length ? filteredTree : null;
      }

      // 初始化结果树
      let resultTree = [];

      // 遍历树的根节点
      for (let rootNode of tree) {
        let filteredNodes = traverseAndFilter(rootNode);
        // 如果filteredNodes不为空,说明找到了匹配项,将其添加到结果树中
        if (filteredNodes) {
          resultTree = resultTree.concat(filteredNodes);
        }
      }

      // 去除重复的节点(如果有的话),因为可能通过多个路径找到了相同的节点
      resultTree = [
        ...new Map(resultTree.map((node) => [node.id || node, node])).values(),
      ];

      // 如果没有找到任何匹配的节点,返回null
      if (resultTree.length === 0) {
        return null;
      }

      // 构建最终的树形结构,只包含匹配的节点及其父节点
      function buildFilteredTree(nodes) {
        const filteredTree = [];
        const nodeMap = new Map();

        for (const node of nodes) {
          nodeMap.set(node.id || node, node);
        }

        for (const node of nodes) {
          const parent = node.parent;
          if (!parent || nodeMap.has(parent)) {
            let currentNode = nodeMap.get(node.id || node);
            let parentNode = parent ? nodeMap.get(parent) : null;

            if (parentNode) {
              if (!parentNode.children) {
                parentNode.children = [];
              }
              parentNode.children.push(currentNode);
              filteredTree.push(parentNode);
            } else {
              filteredTree.push(currentNode);
            }
          }
        }

        return filteredTree;
      }

      // 如果找到了匹配的节点,则构建最终的树形结构
      if (resultTree.length > 0) {
        return buildFilteredTree(resultTree);
      }

      // 如果没有找到匹配的节点,返回null
      return null;
    },
  },
  watch: {
    value() {
      this.valueId = this.value;
      this.initHandle();
    },
    filterText(val) {
      if (val) {
        try {
          this.$refs.selectTree.filter(val);
        } catch (error) {}
      }
    },
  },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
  height: auto;
  max-height: 274px;
  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;
}
.selectInput {
  padding: 0 5px;
  box-sizing: border-box;
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vMware WorkStation创建虚拟机安装CentOS7,NAT模式配置网络

一、安装虚拟机 1、选择典型&#xff08;推荐&#xff09;配置 2、选择稍后安装操作系统 3、操作系统选择CentOS7 64位 4、虚拟机命名、选择安装位置 6、指定磁盘容量 7、指定磁盘容量 步骤&#xff1a; &#xff08;1&#xff09;、系统内存2GB &#xff08;2&#xff09;、…

c++中string的模拟实现(超详细!!!)

1.string的成员变量、&#xff08;拷贝&#xff09;构造、析构函数 1.1.成员变量 private:char* _str;size_t _size; //string中有效字符个数size_t _capacity; //string中能存储有效字符个数的大小 1.2&#xff08;拷贝&#xff09;构造函数 //构造函数string(const char* …

IDEA 2022.1以上版本 配置使用新UI

1、进入此页面的快捷建CtrlAltShift/ 2、新UI配置 3、原设置

算法练习:二分查找

目录 1. 朴素二分查找2. 在排序数组中查找元素的第一个和最后一个位置3. 搜索插入位置4. x的平方根5. 山脉数组的峰值索引6. 寻找峰值7. 寻找旋转排序数组中的最小值8. 点名 1. 朴素二分查找 题目信息&#xff1a; 题目链接&#xff1a; 二分查找二分查找的使用前提为数据具有&…

System类 --java学习笔记

System System代表程序所在的系统&#xff0c;也是一个工具类 常见System方法&#xff1a; 按照惯例&#xff0c;exit括号中非零状态码表示异常终止&#xff0c;填零则表示人为终止 currentTimeMillis&#xff08;&#xff09;返回的是long类型的时间毫秒值&#xff1a;指的…

iOS增量报告生成方案

一&#xff0c;iOS覆盖率报告生成逻辑 iOS覆盖率报告生成与Android有很大的不同&#xff0c;主要的生成逻辑如下&#xff1a; 1&#xff0c;将profraw文件&#xff0c;通过命令xcrun llvm-profdata merge -sparse转换成profdata; 2&#xff0c;再将profdata文件&#xff0c;通…

SCI 机器视觉领域期刊,审稿周期

(1)pattern recognition letters, 从投稿到发表&#xff0c;一年半时间 (2)Pattern recognition 不好中&#xff0c;时间长 (3)IEICE Transactions on Information and Systems&#xff0c; 作者中有一个必须是会员。收费高&#xff0c;审稿快。影响因子0.4 (4)Internationa…

SpringBoot实战项目——博客笔记项目

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍二、项目的整体框架 2.1 数据库模块 2.2 前端模块 2.3 后端模块三、项目图片展示四、项目的实现 4.1 准备工作 4.…

PHP爬虫技术:利用simple_html_dom库分析汽车之家电动车参数

摘要/导言 本文旨在介绍如何利用PHP中的simple_html_dom库结合爬虫代理IP技术来高效采集和分析汽车之家网站的电动车参数。通过实际示例和详细说明&#xff0c;读者将了解如何实现数据分析和爬虫技术的结合应用&#xff0c;从而更好地理解和应用相关技术。 背景/引言 随着电…

git svn混用

背景 项目代码管理初始使用的svn, 由于svn代码操作&#xff0c;无法在本地暂存&#xff0c;有诸多不便&#xff0c;另外本人习惯使用git. 所以决定迁移至git管理 迁移要求&#xff1a; 保留历史提交记录 迁移流程 代码检出 git svn svn_project_url git代码提交 修改本…

突然估摸出了chrome数据的备份

首先是下载 其默认下载到c盘。 我们打开刚刚安装的chrome的位置&#xff0c; 我电脑上是 C:\Users\Lenovo\AppData\Local\Google\Chrome\Application 第一个文件名和版本号对应。 我们查看其上级目录&#xff0c;可以发现有个User Data&#xff0c;这个文件夹里面存放的就是…

发送短信验证码

​​​​​​【短信验证码-快速报备签名】三网短信接口-短信-短信验证码-短信服务-三网短信接口-短信-三网短信【最新版】_商业智能_电商_金融-云市场-阿里云阿里云云市场提供 专注企业短信服务10年运营与技术积累&#xff0c;稳定、安全、快速。服务&#xff0c;建站服务&…

雷达图相关

1.中间显示数字 title: {text: 88,x: center,y: center,textStyle: {color: #333,fontWeight: bolder,fontSize: 64,} } 2.提示信息 tooltip: {trigger: item, // 当鼠标悬浮在某个数据项上时触发}, 3.修改中间颜色 默认&#xff1a; splitArea: {areaStyle: {color: [rgba(…

初识Spring MVC

什么是Spring MVC? 官方给的解释是 Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从⼀开始就包含在 Spring 框架中。它的 正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc)&#xff0c;但它通常被称为"Spring MVC" 注:Severlet是…

近700所高校,2024年预算出炉!

办学经费&#xff0c;是高校发展的核心与基石。学校人才培养、科学研究等各项事业的开展&#xff0c;都有赖于教育经费的支持。 近日&#xff0c;全国已有北京、上海、江苏、浙江等20多个省&#xff08;市、自治区&#xff09;的高校对外公布了2024年预算经费&#xff0c;小编…

阳光保险MySQL数据库平稳迁移OceanBase,稳定运营超700天

作者简介&#xff1a; 车东兴&#xff1a;于阳光保险就职&#xff0c;深耕保险行业的 IT 领域长达12 年&#xff0c;对保险领域的基础架构实践有深刻的理解与掌握。熟悉多款数据库&#xff0c;具有丰富的数据库运维经验。 王华城&#xff1a;于阳光保险就职&#xff0c;10多年一…

中科数安 | 电子文档加密软件——企业数据资料防泄密系统

整体介绍&#xff1a; 中科数安电子文档加密软件&#xff0c;作为一款专为企业级数据安全打造的核心产品&#xff0c;它将尖端加密技术与智能管理策略完美融合&#xff0c;为您企业的核心电子文档提供全方位、多层次的安全防护。我们的加密软件不仅能实现文档的透明加密&#x…

【论文阅读】IEEE Access 2019 BadNets:评估深度神经网络的后门攻击

文章目录 一.论文信息二.论文内容1.摘要2.引言3.主要图表4.结论 一.论文信息 论文题目&#xff1a; BadNets: Evaluating Backdooring Attacks on Deep Neural Networks&#xff08;BadNets:评估深度神经网络的后门攻击&#xff09; 论文来源&#xff1a; 2019-IEEE Access …

【C语言】字符串函数下

&#x1f451;个人主页&#xff1a;啊Q闻 &#x1f387;收录专栏&#xff1a;《C语言》 &#x1f389;道阻且长&#xff0c;行则将至 前言 这篇博客是字符串函数下篇&#xff0c;主要是关于长度受限制的字符串函数&#xff08;strncpy,strncat,strncmp)的使用…

【绘图案例-通过storyboard使用Modal Objective-C语言】

一、继续之前的Modal,刚才讲了通过代码使用Modal,继续说如何通过storyboard来使用Modal, 1.先选中这一段代码, 删掉, 再来到TestViewController.m文件里边,选中这一段代码,也删掉, 这个也无所谓啊,这个类,直接删了就行, 选中这个类,Delete,选择Move to Trash, …