自定义树形筛选选择组件

先上效果图

思路:刚开始最上面我用了el-input,选择框里面内容用了el-input+el-tree使用,但后面发现最上面那个可以输入,那岂不是可以不需要下拉就可以使用,岂不是违背了写这个组件的初衷,所以后面改成div自定义框

组件用法:上面框是你点击下面树形后自动填写到上面去,树形上面的筛选数据框是筛选树形数据的

代码可能没考虑那么周全,暂时还没加上校验,加了禁用点击和选择,属性是disabled

前提:请安装element ui组件,不会的参照:安装Element UI

2024年4月8日 加入一些优化和校验

代码结构:

上组件代码:在components创建customSelectTree文件夹下创建index.vue

<template>
  <div>
    <div class="cTree">
      <!-- 可点击可下拉选择组件 -->
      <div class="cTree-input">
        <span v-if="title" class="cTree-input-title">{{ title }}:</span>
        <div style="white-space: nowrap; position: relative">
          <div class="cTree-input-value">{{ value }}</div>
          <div class="cTree-input-value-icon">
            <i
              style="padding-right: 5px"
              class="el-icon-circle-close"
              v-show="value"
              @click.stop="(value = ''), (id = '')"
            ></i>
            <i
              :style="{ transform: visible ? 'rotate(180deg)' : '' }"
              class="el-icon-arrow-down"
              @click.stop="visible = !visible"
            ></i>
          </div>
        </div>
        <el-button @click="confirm">按钮</el-button>
      </div>
      <div>
        <div class="item__error" v-show="showError">{{ tips }}</div>
        <div class="cTree-box" v-if="visible">
          <div class="cTree-box-input">
            <el-input
              v-model="filterText"
              :placeholder="inputPlaceholder"
              clearable
            />
          </div>
          <div class="cTree-box-content">
            <el-tree
              ref="tree"
              node-key="label"
              default-expand-all
              :highlight-current="true"
              :expand-on-click-node="false"
              :data="treeList"
              :filter-node-method="filterNode"
              :props="defaultProps"
              @node-click="handleNodeClick"
            >
              <span class="custom-tree-node" slot-scope="{ node }">
                <span
                  :style="{
                    cursor: node.disabled === true ? 'not-allowed' : '',
                  }"
                  >{{ node.label }}</span
                >
              </span>
            </el-tree>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'custonTree',
  props: {
    // 传入下拉框数据
    treeList: {
      type: Array,
      default: () => [],
    },
    // 标题
    title: {
      type: String,
      default: '',
    },
    inputPlaceholder: {
      type: String,
      default: '输入可模糊查询',
    },
    defaultProps: {
      type: Object,
      default: () => ({
        children: 'children',
        label: 'label',
        disabled: function (data) {
          if (data.disabled === true) {
            return true;
          }
        },
      }),
    },
    tips: {
      type: String,
      default: '请输入',
    },
  },
  data() {
    return {
      showError: false, //是否展示错误提示
      value: '', //点击后显示在上面的值
      filterText: '',
      label: '',
      visible: false,
      id: '', //点击后后端需要的id
    };
  },
  mounted() {
    let that = this;
    document.addEventListener('click', (e) => {
      if (!that.$el.contains(e.target)) this.visible = false;
    });
  },
  watch: {
    filterText(val) {
      this.$refs.tree.filter(val);
    },
    value: {
      handler(val) {
        if (!val) {
          this.showError = true;
        } else {
          this.showError = false;
        }
      },
    },
  },
  methods: {
    confirm() {
      if (!this.value) {
        this.showError = true;
      } else {
        this.showError = false;
      }
    },
    toValidate() {
      if (!this.value) {
        this.showError = true;
        return true;
      } else {
        this.showError = false;
        return false;
      }
    },
    disabled(data) {
      if (data.disabled === true) {
        return true;
      }
    },
    filterNode(value, data, node) {
      if (!value) return true;
      let _array = [];
      this.getReturnNode(node, _array, value);
      let result = false;
      _array.forEach((item) => {
        result = result || item;
      });
      return result;
    },
    getReturnNode(node, _array, value) {
      let isPass = node && node.label && node.label.indexOf(value) !== -1;
      isPass ? _array.push(isPass) : '';
      if (!isPass && node.children) {
        this.getReturnNode(node.children, _array, value);
      }
    },

    handleNodeClick(data) {
      if (data.disabled === true) return;
      this.value = data.label;
      this.id = data.id;
      // this.$emit(data);
    },
    clickTitle() {
      if (this.visible === true) {
        this.visible = false;
      }
    },
  },
};
</script>
<style lang="scss" scoped>
.cTree {
  &-input {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    box-sizing: border-box;
    color: #ffffff;
    font-size: 14px;
    border-radius: 4px;
    // cursor: pointer;
    margin-right: 20px;
    ::v-deep .el-icon-arrow-down,
    .el-icon-circle-close {
      color: #c0c4cc;
      font-size: 18px;
      cursor: pointer;
    }
    &-title {
      font-size: 14px;
      color: #606266;
      line-height: 40px;
      padding: 0 12px 0 0;
      box-sizing: border-box;
    }
    &-value {
      -webkit-appearance: none;
      background-color: #fff;
      background-image: none;
      border-radius: 4px;
      border: 1px solid #dcdfe6;
      box-sizing: border-box;
      color: #606266;
      display: inline-block;
      height: 40px;
      line-height: 40px;
      outline: 0;
      padding: 0 15px;
      transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
      width: 250px;
      &-icon {
        position: absolute;
        right: 0;
        top: 50%;
        transform: translateY(-50%);
        padding-right: 10px;
      }
    }
  }

  &-box {
    position: absolute;
    user-select: none;
    border-radius: 6px;
    margin-top: 12px;
    width: 300px;
    z-index: 99;
    border: 1px solid #f0f0f0;
    box-shadow: 5px 5px 5px #efefef;
    &:after {
      content: '';
      position: absolute;
      margin-top: -11px;
      top: 0;
      left: 57%;
      width: 0;
      height: 0;
      border-left: 10px solid transparent;
      border-right: 10px solid transparent;
      border-bottom: 10px solid #e8eaec;
      // margin-left: 120px;
      // box-shadow: 10px 5px 5px #efefef;
    }
    &-input {
      padding: 2px 6px;
    }
    &-content {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      color: #606266;
      font-size: 14px;
      line-height: 34px;
      box-sizing: border-box;
      cursor: pointer;
      max-height: 250px;
      overflow-y: auto;
    }
  }
}
::v-deep .el-input__inner {
  position: relative;
}
.item__error {
  color: #f56c6c;
  font-size: 12px;
  line-height: 1;
  padding-top: 4px;
  // position: absolute;
  // top: 100%;
  // left: 0;
}
</style>

使用:

<template>
  <div id="app">
    <CustonBtn ref="cb" :treeList="treeList" />
    <el-button style="height: 40px" @click="toValidate">校验</el-button>
  </div>
</template>

<script>
import CustonBtn from '@/components/customSelectTree/index.vue';

export default {
  name: 'App',
  components: {
    CustonBtn,
  },
  data() {
    return {
      treeList: [
        {
          label: '一级1',
          disabled: true,
          id: '1',
          children: [
            {
              label: '二级1-1',
              disabled: true,
              id: '11',
              children: [
                {
                  label: '三级1-1-1',
                  disabled: false,
                  id: '111',
                },
              ],
            },
          ],
        },
        {
          label: '一级2',
          disabled: true,
          id: '2',
          children: [
            {
              label: '二级2-1',
              disabled: true,
              id: '21',
              children: [
                {
                  label: '三级2-1-1',
                  disabled: false,
                  id: '211',
                },
              ],
            },
            {
              label: '二级2-2',
              disabled: true,
              id: '22',
              children: [
                {
                  label: '三级2-2-1',
                  disabled: false,
                  id: '221',
                },
              ],
            },
          ],
        },
        {
          label: '一级3',
          disabled: true,
          id: '3',
          children: [
            {
              label: '二级3-1',
              disabled: true,
              id: '31',
              children: [
                {
                  label: '三级3-1-1',
                  disabled: false,
                  id: '311',
                },
              ],
            },
            {
              label: '二级3-2',
              disabled: true,
              id: '32',
              children: [
                {
                  label: '三级3-2-1',
                  disabled: false,
                  id: '321',
                },
              ],
            },
          ],
        },
      ],
    };
  },
  methods: {
    // true 校验不通过 false 校验通过
    toValidate() {
      let isTrue = this.$refs.cb.toValidate();
      console.log('isTrue', isTrue);
    },
  },
};
</script>

<style scoped>
#app {
  display: flex;
}
</style>

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

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

相关文章

【ZZULIOJ】1053: 正弦函数(Java)

目录 题目描述 输入 输出 样例输入 Copy 样例输出 Copy code 题目描述 输入x&#xff0c;计算上面公式的前10项和。 输入 输入一个实数x。 输出 输出一个实数&#xff0c;即数列的前10项和&#xff0c;结果保留3位小数。 样例输入 Copy 1 样例输出 Copy 0.841 c…

求三角形面积(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> # include <math.h>int main() {//初始化变量值&#xff1b;double a, b, c, s, area;//赋值&#xff1b;a 3.67;b 5.43;c 6.21;//运算求s&#xff1b…

快速掌握SpringBoot多环境开发

多环境开发 在一个项目当中可能同一套代码需要用于多种环境进行不同的用途例如&#xff1a;生产环境&#xff0c;开发环境&#xff0c;测试环境&#xff0c;需要通过配置进行不同环境的开发切换&#xff1a; spring:profiles:active: shengchan # 通过属性active进行选择 …

二阶巴特沃兹滤波器的数字推导

二阶巴特沃兹滤波器的数字推导 原型双线性变换no warpper双线性变换warpper或者 参考 原型 H ( s ) Ω c 2 s 2 2 ∗ Ω ∗ s Ω c 2 H(s)\frac{\Omega_c^2}{s^2\sqrt{2}*\Omega * s\Omega_c^2} H(s)s22 ​∗Ω∗sΩc2​Ωc2​​ 双线性变换no warpper Ω c ω c T \Omega…

Elastic:加速生成式人工智能体验

作者&#xff1a;Matt Riley 搜索驱动的人工智能和开发人员工具专为速度和规模而打造。 在大型语言模型&#xff08;LLM&#xff09;和生成式 AI 的每日突破中&#xff0c;开发者站在了这场运动的最前沿&#xff0c;影响着它的方向和可能性。在这篇博客中&#xff0c;我将分享…

STL容器之unordered_map类

文章目录 STL容器之unordered_map类1、unordered_map1.1、unordered_map介绍1.2、unordered_map的使用1.2.1、unordered_map的常见构造1.2.2、unordered_map的迭代器1.2.3、unordered_map的容量1.2.4、unordered_map的增删查1.2.5、unordered_map的桶操作 2、unordered_multima…

白盒测试-条件覆盖

​ 条件覆盖是指运行代码进行测试时&#xff0c;程序中所有判断语句中的条件取值为真值为假的情况都被覆盖到&#xff0c;即每个判断语句的所有条件取真值和假值的情况都至少被经历过一次。 ​ 条件覆盖率的计算方法为&#xff1a;测试时覆盖到的条件语句真、假情况的总数 / 程…

redis开源协议变更了?我们还能用吗?

Redis是一款广泛使用的开源键值存储数据库&#xff0c;其开源协议的变更引起了社区和行业的广泛关注。根据搜索结果&#xff0c;Redis Labs宣布Redis将采用双重源代码可用许可证&#xff08;RSALv2&#xff09;和服务器端公共许可证&#xff08;SSPLv1&#xff09;&#xff0c;…

AI自我推理和规划,OpenAI和Meta今年要打开“潘多拉盒子”了 油价100美元几乎已经成了华尔街的共识

OpenAI和Meta今年要打开“潘多拉盒子”了 OpenAI首席运营官Brad Lightcap表示&#xff0c;“我们将开始看到AI能够以更复杂的方式执行更复杂的任务。” OpenAI和Meta正准备发布新的AI模型&#xff0c;他们称这些模型将能够进行自我推理和规划&#xff0c;而这是实现机器“超…

Jmeter —— 自动录制脚本

1、Jmeter配置 1.1新增一个线程组 1.2Jmeter中添加HTTP代理 1.3配置HTTP代理服务器 修改端口 修改Target Cintroller(目标控制器) 修改Grouping(分组) 编辑录制中的包含和排除 在“URL Patterns to include包含模式”中填入.*(123456).*用以过滤请求地址中不包含123456的请求…

设计模式-接口隔离原则

基本介绍 客户端不应该依赖它不需要的接口&#xff0c;即一个类对另一个类的依赖应该建立在最小的接口上先看一张图: 类A通过接口Interface1 依赖类B&#xff0c;类C通过接口Interface1 依赖类D&#xff0c;如果接口Interface1对于类A和类C来说不是最小接口&#xff0c;那么类…

LangChain入门:17.使用 ConversationChain实现对话记忆功能

在默认情况下&#xff0c;无论是 LLM 还是代理都是无状态的&#xff0c;每次模型的调用都是独立于其他交互的。也就是说&#xff0c;我们每次通过 API 开始和大语言模型展开一次新的对话&#xff0c;它都不知道你其实昨天或者前天曾经和它聊过天了。 你肯定会说&#xff0c;不可…

3.2.k8s搭建-kubeadm

目录 一、虚拟机准备 二、所有节点环境准备 1.所有节点做hosts解析 2.所有节点重新命名 3.所有节点安装docker 4.所有节点为docker做linux内核转发 5.所有节点配置docker 6.所有节点关闭swap分区 7.所有节点验证网卡硬件编号是否冲突 8.所有节点配置允许iptables桥接…

【HTML】简单制作一个分形动画

目录 前言 开始 HTML部分 效果图 ​编辑​编辑​编辑​编辑总结 前言 无需多言&#xff0c;本文将详细介绍一段代码&#xff0c;具体内容如下&#xff1a; 开始 首先新建文件夹&#xff0c;创建一个文本文档&#xff0c;其中HTML的文件名改为[index.html]&a…

【原创教程】Smart200通过Modbus RTU实现V90位置控制的方法

1 绪论 1.1 本文的目的 S7-200Smart 可通过标准的 Modbus 功能块发送伺服驱动器的控制指令及读写驱动器的参数。本文详细叙述了 S7-200 SMART PLC 通过 Modbus RTU 通信连接 SINAMICS V90 实现内部位置的 MDI 功能。(MDI(Manual Data Input)称为设定值直接给定运行方式。…

岛屿个数c++

参考文章 岛屿个数1岛屿个数2 题目 输入样例&#xff1a; 2 5 5 01111 11001 10101 10001 11111 5 6 111111 100001 010101 100001 111111输出样例&#xff1a; 1 3样例解释 对于第一组数据&#xff0c;包含两个岛屿&#xff0c;下面用不同的数字进行了区分&#xff1a; 0…

计算机网络-TCP基础、三次挥手、四次握手过程

TCP基础 定义&#xff1a;TCP是面向连接的、可靠的、基于字节流的传输层通信协议。这意味着在发送数据之前&#xff0c;TCP需要建立连接&#xff0c;并且它能确保数据的可靠传输。此外&#xff0c;TCP将数据视为无结构的连续字节流。面向连接&#xff1a;TCP只能一对一进行连接…

Harmony与Android项目结构对比

主要文件对应 Android文件HarmonyOS文件清单文件AndroidManifest.xmlmodule.json5Activity/Fragmententryability下的ts文件XML布局pages下的ets文件resresourcesModule下的build.gradleModule下的build-profile.json5gradlehvigor根目录下的build.gradle根目录下的build-profi…

动态内存管理详解

一.为什么要存在动态内存分配&#xff1a; 下图是不同类型数据在内存中的分配&#xff1a; 上述的开辟空间的⽅式有两个特点&#xff1a; • 空间开辟⼤⼩是固定的。 • 数组在申明的时候&#xff0c;必须指定数组的⻓度&#xff0c;数组空间⼀旦确定了⼤⼩不能调整 但是对…

DeepStream做对象模糊的几种方法

有时候&#xff0c;我们需要对视频的敏感信息做模糊处理&#xff0c;比如模糊人脸&#xff0c;车牌。 有时候&#xff0c;也需要对整帧做模糊&#xff0c;或者遮挡。比如这个例子。 下面介绍几种模糊的办法。 1. 通过nvosd deepstream-test1是DeepStream最简单的一个例子&…