el-select 和el-tree二次封装

前言

本文章是本人在开发过程中,遇到使用树形数据,动态单选或多选的需求,element中没有这种组件,故自己封装一个,欢迎多多指教

开发环境:element-UI、vue2

组件效果

单选

多选

组件引用

<treeselect v-model="form.parentId"
                      :options="deptOptions"
                      :props="{value:'id',label:'name',children: 'children'}"
                      :placeholder="'选择上级部门'"
          />

组件代码

<template>
  <div>
    <el-select
      ref="treeSelect"
      popper-class="custom-select-popper"
      style="width: 100%"
      v-model="valueLabel"
      :clearable="clearable"
      :placeholder="placeholder"
      :multiple="multiple"
      @clear="handleClear"
      @remove-tag="handleRemoveTag"
    >
      <el-input v-if="filter"
                v-model="filterText"
                :placeholder="filterPlaceholder" style="margin-top: -6px;"
      />
      <el-option :value="value" :label="option.name" class="select-options">
        <el-tree
          id="tree-option"
          ref="treeSelectTree"
          :accordion="accordion"
          :data="options"
          :props="props"
          :node-key="props.value"
          :highlight-current="!multiple"
          :show-checkbox="multiple"
          :check-strictly="checkStrictly"
          :default-expand-all="expandAll"
          :expand-on-click-node="multiple"
          :filter-node-method="filterNode"
          @node-click="handleNodeClick"
          @check="handleNodeCheckbox"
        >
          <span slot-scope="{ node, data }" class="tree_label">
                {{ node.label }}
              </span>
        </el-tree>
      </el-option>
    </el-select>
  </div>
</template>
<script>
export default {
  name: 'TreeSelect',
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    value: {
      type: [String, Number, Object, Array],
      default: () => {
        return ''
      }
    },
    clearable: {
      type: Boolean,
      default: true
    },
    placeholder: {
      type: String,
      default: '请选择'
    },
    multipleLimit: {
      type: Number,
      default: 2
    },
    //--------- filter props -----
    filter: {
      type: Boolean,
      default: true
    },
    filterPlaceholder: {
      type: String,
      default: '请输入关键字'
    },
    //----- tree props -----
    accordion: {
      type: Boolean,
      default: false
    },
    options: {
      type: Array,
      default: () => {
        return []
      }
    },
    props: {
      type: Object,
      default: () => {
        return {
          value: 'id',
          label: 'label',
          children: 'children'
        }
      }
    },
    expandAll: {
      type: Boolean,
      default: false
    },
    checkStrictly: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      tp: {
        value: 'id',
        label: 'label',
        children: 'children',
        prentId: 'parentId'
      },
      multiple: false,
      valueLabel: [],
      option: {
        id: '',
        name: ''
      },
      filterText: undefined,
      valueId: [],
      treeIds: []
    }
  },
  watch: {
    valueId() {
      if (this.multiple) {
        let valueStr = ''
        if (this.value instanceof Array) {
          valueStr = this.value.join()
        } else {
          valueStr = '' + this.value
        }
        if (valueStr !== this.valueId.join()) {
          this.$emit('change', this.valueId)
        }
      } else {
        let id = this.valueId.length > 0 ? this.valueId[0] : undefined
        if (id !== this.value) {
          this.$emit('change', id)
        }
      }
    },
    value: {
      handler(newVal, oldVal) {
        if (newVal !== oldVal) {
          this.init()
        }
      }
    },
    filterText: {
      handler(newVal, oldVal) {
        if (newVal !== oldVal) {
          this.$refs.treeSelectTree.filter(newVal)
        }
      }
    }
  },
  mounted() {
    for (let key in this.tp) {
      if (this.props[key] !== undefined) {
        this.tp[key] = this.props[key]
      }
    }
    this.multiple = this.multipleLimit > 1
    this.init()
    this.$nextTick(() => {
      if (this.multiple) {
        document.getElementsByClassName('el-select__tags')[0].style.maxHeight = document.getElementsByClassName('el-select')[0].offsetHeight * 2 - 4 + 'px'
      }
    })

  },
  methods: {
    init() {
      if (this.value instanceof Array) {
        this.valueId = this.value
      } else if (this.value === undefined) {
        this.valueId = []
      } else {
        this.valueId = [this.value]
      }
      if (this.multiple) {
        for (let id of this.valueId) {
          this.$refs.treeSelectTree.setChecked(id, true, false)
        }
      } else {
        this.$refs.treeSelectTree.setCurrentKey(this.valueId.length > 0 ? this.valueId[0] : undefined)
      }
      this.initValueLabel()
      this.initTreeIds()
      this.initScroll()
    },
    // 初始化滚动条
    initScroll() {
      this.$nextTick(() => {
        let scrollWrap = document.querySelectorAll('.el-scrollbar .el-select-dropdown__wrap')[0]
        scrollWrap.style.cssText = 'margin: 0px; max-height: none; overflow: hidden;'
        let scrollBar = document.querySelectorAll('.el-scrollbar .el-scrollbar__bar')
        scrollBar.forEach((ele) => (ele.style.width = 0))
      })
    },
    initTreeIds() {
      let treeIds = []
      let _this = this

      function traverse(nodes) {
        for (let node of nodes) {
          treeIds.push(node[_this.tp.value])
          if (node[_this.tp.children]) {
            traverse(node[_this.tp.children])
          }
        }
      }

      traverse(this.options)
      this.treeIds = treeIds
    },
    initValueLabel() {
      let labels = []
      let _this = this
      for (let id of this.valueId) {
        let node = this.traverse(this.options, node => node[_this.tp.value] === id)
        if (node) {
          labels.push(node[_this.tp.label])
        }
      }
      if (this.multiple) {
        this.valueLabel = labels
        this.option.name = labels.join()
      } else {
        this.valueLabel = labels.length > 0 ? labels[0] : undefined
        this.option.name = this.valueLabel
      }
    },
    traverse(tree, func) {
      for (let node of tree) {
        if (func(node)) {
          return node
        }
        if (node[this.tp.children]) {
          let result = this.traverse(node[this.tp.children], func)
          if (result !== undefined) {
            return result
          }
        }
      }
      return undefined
    },
    handleClear() {
      this.valueLabel = []
      this.valueId = []
      if (this.multiple) {
        for (let id of this.treeIds) {
          this.$refs.treeSelectTree.setChecked(id, false, false)
        }
      } else {
        this.$refs.treeSelectTree.setCurrentKey(null)
      }
    },
    /* 树filter方法 */
    filterNode(value, data) {
      if (!value) return true
      return data[this.props.label].indexOf(value) !== -1
    },
    /* 树节点点击事件 */
    handleNodeClick(data, node) {
      if (!this.multiple) {
        this.filterText = ''
        this.valueId = [data[this.tp.value]]
      }
      if(node.childNodes){
        node.expanded = true
      }
    },
    handleNodeCheckbox(data, node) {
      if (this.multiple) {
        if (this.multipleLimit >= node.checkedKeys.length) {
          this.valueId = node.checkedKeys
        } else {
          this.$refs.treeSelectTree.setChecked(data, false, !this.checkStrictly)
          this.$message.error('最多选择' + this.multipleLimit + '项')
        }
      }
    },
    handleRemoveTag(tag) {
      let n = this.traverse(this.options, node => node[this.tp.label] === tag)
      if (n) {
        this.$refs.treeSelectTree.setChecked(n[this.tp.value], false, !this.checkStrictly)
      }
      this.valueId = this.$refs.treeSelectTree.getCheckedKeys()
    }
  }
}

</script>

<style scoped lang="scss">
::v-deep .el-select__tags {
  overflow: auto;
}
.custom-select-popper{

}

.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;
    }
    .is-current > .el-tree-node__label{
      color: #409eff;
      font-weight: 700;
    }
  }
}


.tree_label {
  line-height: 23px;

  .label_index {
    background-color: rgb(0, 175, 255);
    width: 22px;
    height: 22px;
    display: inline-flex;
    border-radius: 4px;

    .label_index_font {
      color: #ffffff;
      width: 100%;
      text-align: center;
    }
  }
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32-- keil常见报错与解决办法

调试问题 1. keil在线调试需要点击好几次运行才可以运行&#xff0c;要是直接下载程序直接就不运行。 解决&#xff1a;target里面的use microlib要勾选&#xff0c;因为使用了printf。 keil在线调试STM32&#xff0c;点三次运行才能跑到main的问题解决。 keil在线调试STM32…

RNN简单理解;为什么出现Transformer:传统RNN的问题;Attention(注意力机制)和Self-Attention(自注意力机制)区别;

目录 RNN简单理解 RNN n to n Transformer N to M LSTM 为什么出现Transformer:传统RNN的问题 信息丢失的后果 Rnn是顺序执行的效率不高:顺序执行 Attention(注意力机制)和Self-Attention(自注意力机制)区别 一、计算对象不同 二、应用场景不同 三、功能差异…

51c深度学习~合集8

我自己的原文哦~ https://blog.51cto.com/whaosoft/12491632 #patchmix 近期中南大学的几位研究者做了一项对比学习方面的工作——「Inter-Instance Similarity Modeling for Contrastive Learning」&#xff0c;主要用于解决现有对比学习方法在训练过程中忽略样本间相似关系…

Kafka:分布式消息系统的核心原理与安装部署

Kafka&#xff1a;分布式消息系统的核心原理与安装部署-CSDN博客 自定义 Kafka 脚本 kf-use.sh 的解析与功能与应用示例-CSDN博客 Kafka 生产者全面解析&#xff1a;从基础原理到高级实践-CSDN博客 Kafka 生产者优化与数据处理经验-CSDN博客 Kafka 工作流程解析&#xff1a…

刷算法题时遇到的一些不常用但好用的API

1.需要统计数据&#xff0c;同时希望数据是排序的&#xff0c;可以使用TreeMap结构。 2.按照ASCII&#xff0c;A的ASCII值比a小。而字典排序底层也有基于ASCII&#xff0c;因此无论是字典排序还是ASCII排序&#xff0c;A都在a前面。 3.使用DecimalFormat尝试将浮点数四舍五入…

2024-11-19 kron积

若A[a11 a12; a21 a22]; B[b11 b12; b21 b22]; 则C[a11*b11 a12*b11 a21*b11 a22*b11; a11*b12 a12*b12 a21*b12 a22*b12; a11*b21 a12*b21 a21*b21 a22*b21; a11*b22 a12*b22 a21*b22 a22*b22] 用MATLAB实现 方法1&#xff1a; A [a11 a12; a21 a22]; B [b11 b12; b21 b22]…

工业生产安全-安全帽第二篇-用java语言看看opencv实现的目标检测使用过程

一.背景 公司是非煤采矿业&#xff0c;核心业务是采选&#xff0c;大型设备多&#xff0c;安全风险因素多。当下政府重视安全&#xff0c;头部技术企业的安全解决方案先进但价格不低&#xff0c;作为民营企业对安全投入的成本很敏感。利用我本身所学&#xff0c;准备搭建公司的…

(7) 探索Python函数的无限可能:从递归到Lambda的奇妙之旅

欢迎进入Python编程的奇幻世界!在这个课程中,我们将一起探索编程的乐趣,通过生动有趣的方式,培养编程的逻辑思维和创造力,该课程适合有一定基础的中学及以上学生及成年人。 以下是我们课程的大纲: 【Python:趣味编程,探索未来】 目录 1. 前言2. 认识我们的“魔法咒语”…

【深度学习|目标跟踪】DeepSort 详解

DeepSort详解 1、Sort回顾2、DeepSort的状态向量3、DeepSort的外观特征4、DeepSort的track状态5、DeepSort的代价矩阵以及门控矩阵6、DeepSort的级联匹配 1、Sort回顾 查看这篇博客 2、DeepSort的状态向量 Sort中的卡尔曼滤波使用的目标的状态向量是一个7维的向量&#xff0c…

MetaGPT实现多动作Agent

异步编程学习链接 智能体 LLM观察思考行动记忆 多智能体 智能体环境SOP评审路由订阅经济 教程地址 多动作的agent的本质是react&#xff0c;这包括了think&#xff08;考虑接下来该采取啥动作&#xff09;act&#xff08;采取行动&#xff09; 在MetaGPT的examples/write_…

重学SpringBoot3-Spring Retry实践

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-Spring Retry实践 1. 简介2. 环境准备3. 使用方式3.1 注解方式基础使用自定义重试策略失败恢复机制重试和失败恢复效果注意事项 3.2 编程式使用3.3 监听…

E. Counting Arrays

题意&#xff1a;给定一个长度为n&#xff0c;要求乘积为m&#xff0c;其中组成m的数要求是整数 思路&#xff1a;首先有个很显然的想法&#xff1a;设表示前i个点乘积为j的最小值。因为询问数很多&#xff0c;所以必须离线把所有的东西都处理出来。 转移&#xff1a;&#x…

Leetcode 生命游戏

以下是上述Java代码的算法思想及其逻辑的中文解释&#xff1a; 算法思想 这段代码实现了LeetCode第289题“生命游戏”的解决方案。核心思想是&#xff1a; 利用原地修改的方式&#xff08;in-place&#xff09;存储下一状态的变化&#xff1a; 通过引入额外的状态值&#xff0…

文件管理 IV(文件系统)

一、文件系统结构 文件系统&#xff08;File system&#xff09;提供高效和便捷的磁盘访问&#xff0c;以便允许存储、定位、提取数据。文件系统有两个不同的设计问题&#xff1a;第一个问题是&#xff0c;定义文件系统的用户接口&#xff0c;它涉及定义文件及其属性、所允许的…

单神经元 PID 解耦控制

单神经元 PID 解耦控制是一种将单神经元自适应控制与解耦控制相结合的方法&#xff0c;适用于多输入多输出&#xff08;MIMO&#xff09;系统。其核心是利用单神经元的自适应能力实现 PID 参数在线调整&#xff0c;同时通过解耦策略减少变量之间的相互影响&#xff0c;提高控制…

【青牛科技】电流模式PWM控制器系列--D4870

概述&#xff1a; D4870是用于开关电源的电流模式PWM(PWM)控制器系列产品。 该电路待机功耗低&#xff0c;启动电流低。在待机模式下&#xff0c;电路进入间歇工作模式&#xff0c;从而有效地降低电路的待机功耗。 电路的开关频率为 65KHz&#xff0c;抖动的振荡频率&…

【8210A-TX2】Ubuntu18.04 + ROS_ Melodic + TM-16多线激光 雷达评测

简介&#xff1a;介绍 TM-16多线激光雷达 在8210A载板&#xff0c;TX2核心模块环境&#xff08;Ubuntu18.04&#xff09;下测试ROS驱动&#xff0c;打开使用RVIZ 查看点云数据&#xff0c;本文的前提条件是你的TX2里已经安装了ROS版本&#xff1a;Melodic。 大家好&#xff0c;…

计算机毕设-基于springboot的高校网上缴费综合务系统视频的设计与实现(附源码+lw+ppt+开题报告)

博主介绍&#xff1a;✌多个项目实战经验、多个大型网购商城开发经验、在某机构指导学员上千名、专注于本行业领域✌ 技术范围&#xff1a;Java实战项目、Python实战项目、微信小程序/安卓实战项目、爬虫大数据实战项目、Nodejs实战项目、PHP实战项目、.NET实战项目、Golang实战…

在 macOS 和 Linux 中,波浪号 `~`的区别

文章目录 1、在 macOS 和 Linux 中&#xff0c;波浪号 ~macOS示例 Linux示例 区别总结其他注意事项示例macOSLinux 结论 2、root 用户的主目录通常是 /root解释示例切换用户使用 su 命令使用 sudo 命令 验证当前用户总结 1、在 macOS 和 Linux 中&#xff0c;波浪号 ~ 在 macO…

【SQL Server】华中农业大学空间数据库实验报告 实验九 触发器

1.实验目的 通过实验课程与理论课的学习深入理解掌握的触发器的原理、创建、修改、删除、基本的使用方法、主要用途&#xff0c;并且可以在练习的基础上&#xff0c;熟练使用触发器来进行数据库的应用程序的设计&#xff1b;深入学习深刻理解与触发器相关的T-SQL语句的编写的基…