vue3 el-select+el-tree实现下拉树形选择

主要功能: 多选,移除标签,清空标签,模糊搜索,禁用,全选,清空

<template>
  <el-select
    v-model="selectValue"
    multiple
    placeholder="请选择"
    :popper-append-to-body="true"
    @remove-tag="removeTag"
    collapse-tags
    collapse-tags-tooltip
    @clear="clearAll"
    clearable
    filterable
    :filter-method="filterMethod"
  >
    <el-option
      v-loading="treeLoading"
      :value="selectTree"
      element-loading-background="rgba(255, 255, 255, 0.5)"
      element-loading-text="loading"
      class="option-style"
      disabled
    >
      <div class="check-box">
        <el-button type="primary" text @click="handleCheckAll">全选</el-button>
        <el-button type="primary" text @click="clearAll">清空</el-button>
      </div>
      <el-tree
        :data="fileTypeTree"
        :props="treeProps"
        ref="tree"
        show-checkbox
        :expand-on-click-node="false"
        node-key="id"
        check-on-click-node
        highlight-current
        @check="handleCheckClick"
        :filter-node-method="filterNode"
        class="tree-style"
      ></el-tree>
    </el-option>
  </el-select>
</template>

<script>
import 'element-plus/dist/index.css'
import { getFileTypeTree } from '@/api/Customer/index'

export default {
  name: 'App',
  data() {
    return {
      noticeTypeId: [], // 最后获取的选择id
      treeProps: {
        value: 'id',
        label: 'name',
        children: 'children',
        isLeaf: 'isLeaf',
      },
      fileTypeTree: [],
      selectValue: [], // 文本框中的标签
      selectTree: [], // 绑定el-option的值
      treeLoading: false,
    }
  },
  async created() {
    // 树结构数据
    const resFile = await getFileTypeTree()
    if (resFile.data.code === 20000) {
      this.fileTypeTree = resFile.data.data
    }

    // 如果noticeTypeId有初始值,需要加入以下代码回显值
    this.$nextTick(() => {
      this.noticeTypeId.forEach((v) => {
        this.$refs.tree.setChecked(v, true, true)
      })
    })
    this.selectTree = this.flattenTree(this.fileTypeTree)
    // 筛选出匹配的对象并返回其 name 属性
    this.selectValue = this.selectTree
      .filter((item) => this.noticeTypeId.includes(item.id)) // 过滤出id匹配的数据
      .map((v) => ({
        label: v.name,
        value: v.id,
      }))
  },
  methods: {
    // 平铺树状结构
    flattenTree(tree) {
      const result = []
      function traverse(node) {
        result.push({
          id: node.id,
          name: node.name,
        })
        if (node.children && node.children.length > 0) {
          node.children.forEach((child) => traverse(child))
        }
      }
      tree.forEach((rootNode) => traverse(rootNode))
      return result
    },
    // 全选
    handleCheckAll() {
      this.treeLoading = true
      setTimeout(() => {
        this.$refs.tree.setCheckedNodes(this.fileTypeTree)
        this.treeLoading = false
      }, 200)
      this.selectTree = this.flattenTree(this.fileTypeTree)
      this.selectValue = this.selectTree.map((v) => ({
        label: v.name,
        value: v.id,
      }))
      this.noticeTypeId = this.selectTree.map((v) => v.id)
    },
    /**
     * @description: 勾选树形选项
     * @param {*} data 传递给 data 属性的数组中该节点所对应的对象
     * @param {*} node  树目前的选中状态对象,包含 checkedNodes、checkedKeys、halfCheckedNodes、halfCheckedKeys 四个属性
     * @return {*}
     */
    handleCheckClick(data, node) {
      console.log('handleCheckClick----', data, node)
      this.selectTree = node.checkedNodes
      this.selectValue = this.selectTree.map((v) => ({
        label: v.name,
        value: v.id,
      }))
      this.noticeTypeId = node.checkedKeys
    },
    removeTag(tag) {
      this.selectValue = this.selectValue.filter((v) => v.id !== tag.value)
      this.selectTree = this.selectTree.filter((v) => v.id !== tag.value)
      this.noticeTypeId = this.selectTree.map((v) => v.id)
      this.$nextTick(() => {
        this.$refs.tree.setCheckedNodes(this.selectTree)
      })
    },
    clearAll() {
      this.treeLoading = true
      this.selectTree = []
      this.selectValue = []
      this.noticeTypeId = []
      setTimeout(() => {
        this.fileTypeTree.forEach((v) => {
          this.$refs.tree.setChecked(v.id, false, true) // 在树状结构没有展开时,使用setChecked才能改变节点状态
        })
        this.treeLoading = false
      }, 200)
    },
    // 输入框关键字
    filterMethod(val) {
      this.$refs.tree.filter(val)
    },
    /**
     * @description: tree搜索过滤
     * @param {*} value 搜索的关键字
     * @param {*} data  筛选到的节点
     * @return {*}
     */
    filterNode(value, data) {
      if (!value) return true
      return data.name.toLowerCase().indexOf(value.toLowerCase()) !== -1
    },
  },
}
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值