Vue3+TS+Element Plus封装树形下拉选择组件

4,835 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

项目上需要有树形结构的下拉选择需要,展示树形结构数据

结合Vue3、TypeScript、Element Plus封装该组件

项目搭建

基于之前文章的框架封装,使用Vite搭建Vue3项目实践记录 - 掘金 (juejin.cn)

已有Vite、Vue3、TypeScript、Element Plus,并带有ESlint代码规范

可根据需要全局引入或按需引入Element Plus

开始

子组件

项目搭建后,在components文件夹下新建treeSelect.vue文件

html部分是el-input、el-popover、el-tree组合而成的,input不需要输入所以要设置readonly

input的值一般是label用作展示的文字,真正选择的值是propsValue

el-treedata、props还有其他的值都可以从父组件传入

<template>
  <div>
    {{ propsValue }}
  </div>
  <el-popover placement="bottom-start" :width="200" trigger="click">
    <template #reference>
      <el-input v-model="state.label" style="width: 240px" readonly placeholder="Please input" />
    </template>
    <el-tree :data="props.treeData" :props="props.defaultProps" @node-click="handleNodeClick" />
  </el-popover>
</template>

js部分是用了script setup的写法

<script lang="ts" setup>
import { computed, reactive } from "vue";

const props = defineProps({
  modelValue: {
    type: String,
    default: ""
  },
  treeData: {
    type: Array,
    default: () => []
  },
  defaultProps: {
    type: Object,
    default: () => {
      return {
        children: "children",
        label: "label"
      };
    }
  }
});
const propsValue = computed(() => props.modelValue);
const state = reactive({
  label: ""
});
const emit = defineEmits(["update:modelValue"]);
const handleNodeClick = (data: any) => {
  state.label = data.label;
  emit("update:modelValue", data.id);
};
</script>

需要注意几点

第一是props中的数组和对象的默认值default都需要用函数返回

第二,modelValue是父组件v-model传入的值,如果在子组件的input中也使用 v-model="props.modelValue"会报错,所以可以选择使用computed返回一个新的值

第三,修改modelValue可以直接可以defineEmits(["update:modelValue"])

父组件

父组件就相对简单,负责传值就可以了

<template>
  <div>
    <tree-select v-model="state.select" :tree-data="state.treeData" :default-props="state.defaultProps"></tree-select>
  </div>
</template>
<script setup lang="ts">
import { reactive } from "vue";
interface Tree {
  id: number;
  label: string;
  children?: Tree[];
}
const state = reactive({
  select: "123",
  treeData: [
    {
      id: 1,
      label: "Level one 1",
      children: [
        {
          id: 11,
          label: "Level two 1-1",
          children: [
            {
              label: "Level three 1-1-1"
            }
          ]
        }
      ]
    },
    {
      id: 2,
      label: "Level one 2",
      children: [
        {
          id: 21,
          label: "Level two 2-1"
        },
        {
          id: 22,
          label: "Level two 2-2",
          children: [
            {
              id: 23,
              label: "Level three 2-2-1"
            }
          ]
        }
      ]
    }
  ] as Tree[],
  defaultProps: {
    id: "id",
    children: "children",
    label: "label"
  }
});
</script>

效果

选择后input展示节点的文字,并改变propValue的值

image.png

Element Plus的树形选择

Element Plus的2.18版本已经支持了树形选择,可单选或多选,建议升级Element Plus使用

TreeSelect 树形选择 | Element Plus (gitee.io)

结束

后续可增加节点禁用,默认打开某些节点

欢迎点赞收藏