vue2结合element-ui实现TreeSelect 树选择功能

效果:
大致思路:

el-select和el-tree进行嵌套,将el-tree放到el-option里,循环遍历el-option,同时定义一个方法比如:formatData,对树形数据进行递归处理,这样就可以实现无论嵌套的层级有几层都可以正常渲染在界面上 利用 v-model 和 update:selectValue 实现父子组件之间的双向通信,同时利用computed进行监听

vue

子组件:TreeSelect.vue

xml 复制代码
<template>
  <div class="app-container" style="padding: 0">
    <el-select
      class="main-select-tree"
      ref="selectTree"
      v-model="value"
      style="width: 240px"
      clearable
      @clear="clearSelectInput"
    >
      <el-input
        style="width: 220px; margin-left: 10px; margin-bottom: 10px"
        placeholder="输入关键字进行过滤"
        v-model="filterText"
        clearable
      >
      </el-input>
      <el-option
        v-for="item in formatData(data)"
        :key="item.value"
        :label="item.label"
        :value="item.value"
        style="display: none"
      />
      <el-tree
        class="main-select-el-tree"
        ref="selecteltree"
        :data="data"
        node-key="id"
        highlight-current
        :props="defaultProps"
        @node-click="handleNodeClick"
        :current-node-key="value"
        :expand-on-click-node="true"
        default-expand-all
        :filter-node-method="filterNode"
      />
    </el-select>
  </div>
</template>
    
    <script>
export default {
  props: {
    selectValue: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      filterText: "",
      value: "",
      data: [
        {
          id: 1,
          label: "云南",
          children: [
            {
              id: 2,
              label: "昆明",
              children: [
                {
                  id: 3,
                  label: "五华区",
                  children: [
                    {
                      id: 8,
                      label: "xx街道",
                      children: [
                        {
                          id: 81,
                          label: "yy社区",
                          children: [{ id: 82, label: "北辰小区" }],
                        },
                      ],
                    },
                  ],
                },
                { id: 4, label: "盘龙区" },
              ],
            },
          ],
        },
        {
          id: 5,
          label: "湖南",
          children: [
            { id: 6, label: "长沙" },
            { id: 7, label: "永州" },
          ],
        },
        {
          id: 12,
          label: "重庆",
          children: [
            { id: 10, label: "渝北" },
            { id: 9, label: "合川" },
          ],
        },
        {
          id: 13,
          label: "江苏",
          children: [{ id: 14, label: "盐城" }],
        },
      ],
      defaultProps: {
        children: "children",
        label: "label",
      },
    };
  },
  watch: {
    filterText(val) {
      this.$refs.selecteltree.filter(val);
    },
  },
  methods: {
    filterNode(value, data) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },
    // 递归遍历数据
    formatData(data) {
      let options = [];
      const formatDataRecursive = (data) => {
        data.forEach((item) => {
          options.push({ label: item.label, value: item.id });
          if (item.children && item.children.length > 0) {
            formatDataRecursive(item.children);
          }
        });
      };
      formatDataRecursive(data);
      return options;
    },
    // 点击事件
    handleNodeClick(node) {
      this.value = node.id;
      this.$refs.selectTree.blur();
      this.$emit('update:selectValue', node.label);
    },
    // 清空事件
    clearSelectInput() {
        this.$emit('update:selectValue', '');
    },
  },
};
</script>
    <style>
.main-select-el-tree .el-tree-node .is-current > .el-tree-node__content {
  font-weight: bold;
  color: #409eff;
}
.main-select-el-tree .el-tree-node.is-current > .el-tree-node__content {
  font-weight: bold;
  color: #409eff;
}
</style>
    

父组件:

vue 复制代码
<TreeSelect v-model="selectedValue" @update:selectValue="handleSelectValueChange"></TreeSelect>

<el-button size="medium" :disabled="todoIsTotal">交接当前{{ tableData.length }}条任务</el-button>
                
import TreeSelect from "./TreeSelect.vue";

export default {
    components: {
        TreeSelect,
    },
    data() {
        selectedValue: "",
    },
    computed: {
        todoIsTotal() {
            return this.selectedValue === "";
        },
    },
    methods: {
        handleSelectValueChange(value) {
            if (value && value.length > 0) {
                this.selectedValue = value;
            } else {
                this.selectedValue = "";
            }
        },
    },
}
相关推荐
IT_陈寒3 分钟前
Vue的这个响应式问题,坑了我整整两小时
前端·人工智能·后端
C澒12 分钟前
AI 生码:A 类生码方案架构升级
前端·ai编程
前端Hardy34 分钟前
前端必看!LocalStorage这么用,再也不踩坑(多框架通用,直接复制)
前端·javascript·面试
前端Hardy34 分钟前
前端必看!前端路由守卫这么写,再也不担心权限混乱(Vue/React通用)
前端·javascript·面试
Lee川1 小时前
从零构建现代化登录界面:React + Tailwind CSS 前端工程实践
前端·react.js
Awu12271 小时前
⚡精通 Claude 第 1 课:掌握 Slash Commands
前端·人工智能·ai编程
竹林8181 小时前
从ethers.js迁移到Viem:我在重构DeFi前端时踩过的那些坑
前端·javascript
码云之上1 小时前
上下文工程实战:解决多轮对话中的"上下文腐烂"问题
前端·node.js·agent
小小弯_Shelby1 小时前
webpack优化:Vue配置compression-webpack-plugin实现gzip压缩
前端·vue.js·webpack
小村儿1 小时前
连载04-CLAUDE.md ---一起吃透 Claude Code,告别 AI coding 迷茫
前端·后端·ai编程