Skip to content

ModelTree 模型树

该组件是 antd Tree 组件的集成,并支持查询功能

何时使用

  • 该组件是 Tree 组件的集成,在任何需要使用 Tree 组件的地方都可以使用 ModelTree

开发者注意事项

  • 开箱即用,只用提供 treeData 即可,我们默认 treeData 的数据结构是 TreeData 类型;

  • 如果 treeData 的数据结构不是TreeData 类型,组件提供了 "formatTreeData" 属性来定义具体的数据格式转换方法;

  • 可以通过 "fieldNames" 字段,告诉组件 treeData 的数据结构,组件会根据传入的 "fieldNames" 自动对 props.treeData 格式化;

  • 设置了 "checkable" 就不要设置 "selectable" 字段了,组件中 "selectable" 将自动取 "checkable" 的反值;

代码演示

案例一(checkable 类型,可以通过 disableCheckbox 控制节点能否可选)

1-1
1-1-1
1-1-1-1
1-1-1-2
1-1-2
1-1-3
1-2
1-3
1-4
vue
<script setup lang="ts">
import { ref } from 'vue';
import { ModelTree } from '@/library';

const checkedKeys = ref(['1-1-1-1']);
const expandedKeys = ref(['1-1', '1-1-1']);
const treeData = ref([
  {
    id: '1-1',
    name: '1-1',
    children: [
      {
        id: '1-1-1',
        parentId: '1-1',
        name: '1-1-1',
        children: [
          {
            id: '1-1-1-1',
            parentId: '1-1-1',
            name: '1-1-1-1',
          },
          {
            id: '1-1-1-2',
            parentId: '1-1-1',
            name: '1-1-1-2',
          },
        ],
      },
      {
        id: '1-1-2',
        parentId: '1-1',
        name: '1-1-2',
      },
      {
        id: '1-1-3',
        parentId: '1-1',
        name: '1-1-3',
      },
    ],
  },
  {
    id: '1-2',
    name: '1-2',
    children: [
      {
        id: '1-2-1',
        parentId: '1-2',
        name: '1-2-1',
      },
      {
        id: '1-2-2',
        parentId: '1-2',
        name: '1-2-2',
        disableCheckbox: true,
        children: [
          {
            id: '1-2-2-1',
            parentId: '1-2-2',
            name: '1-2-2-1',
          },
          {
            id: '1-2-2-2',
            parentId: '1-2-2',
            name: '1-2-2-2',
          },
        ],
      },
    ],
  },
  {
    id: '1-3',
    name: '1-3',
  },
  {
    id: '1-4',
    name: '1-4',
  },
]);

const fieldNames = {
  key: 'id',
  title: 'name',
  parentKey: 'parentId',
};
</script>

<template>
  <ModelTree
    v-model:checkedKeys="checkedKeys"
    v-model:expandedKeys="expandedKeys"
    multiple
    :bordered="false"
    :treeData="treeData"
    :fieldNames="fieldNames"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ModelTree } from '@/library';

const checkedKeys = ref(['1-1-1-1']);
const expandedKeys = ref(['1-1', '1-1-1']);
const treeData = ref([
  {
    id: '1-1',
    name: '1-1',
    children: [
      {
        id: '1-1-1',
        parentId: '1-1',
        name: '1-1-1',
        children: [
          {
            id: '1-1-1-1',
            parentId: '1-1-1',
            name: '1-1-1-1',
          },
          {
            id: '1-1-1-2',
            parentId: '1-1-1',
            name: '1-1-1-2',
          },
        ],
      },
      {
        id: '1-1-2',
        parentId: '1-1',
        name: '1-1-2',
      },
      {
        id: '1-1-3',
        parentId: '1-1',
        name: '1-1-3',
      },
    ],
  },
  {
    id: '1-2',
    name: '1-2',
    children: [
      {
        id: '1-2-1',
        parentId: '1-2',
        name: '1-2-1',
      },
      {
        id: '1-2-2',
        parentId: '1-2',
        name: '1-2-2',
        disableCheckbox: true,
        children: [
          {
            id: '1-2-2-1',
            parentId: '1-2-2',
            name: '1-2-2-1',
          },
          {
            id: '1-2-2-2',
            parentId: '1-2-2',
            name: '1-2-2-2',
          },
        ],
      },
    ],
  },
  {
    id: '1-3',
    name: '1-3',
  },
  {
    id: '1-4',
    name: '1-4',
  },
]);

const fieldNames = {
  key: 'id',
  title: 'name',
  parentKey: 'parentId',
};
</script>

<template>
  <ModelTree
    v-model:checkedKeys="checkedKeys"
    v-model:expandedKeys="expandedKeys"
    multiple
    :bordered="false"
    :treeData="treeData"
    :fieldNames="fieldNames"
  />
</template>

案例二(selectable 类型,通过 disabled 控制节点能否可选)

1-1
1-2
vue
<script setup lang="ts">
import { ModelTree } from '@/library';
import type { TreeData } from '@/library/ModelTree';
import { ref, watch, onMounted } from 'vue';
const selectedKeys = ref<string[]>([]);
const expandedKeys = ref<string[]>([]);
const modelTreeRef = ref<InstanceType<typeof ModelTree>>();

onMounted(() => {
  selectedKeys.value = ['1-1-1-1'];
  expandedKeys.value = ['1-1', '1-1-1'];
});

const treeData = ref([
  {
    sid: '1-1',
    title: '1-1',
    // 不可选
    disabled: true,
    children: [
      {
        sid: '1-1-1',
        parentSid: '1-1',
        name: '1-1-1',
        // 不可选
        disabled: true,
        children: [
          {
            sid: '1-1-1-1',
            parentSid: '1-1-1',
            name: '1-1-1-1',
          },
          {
            sid: '1-1-1-2',
            parentSid: '1-1-1',
            name: '1-1-1-2',
          },
        ],
      },
      {
        sid: '1-1-2',
        parentSid: '1-1',
        name: '1-1-2',
      },
      {
        sid: '1-1-3',
        parentSid: '1-1',
        name: '1-1-3',
      },
    ],
  },
  {
    sid: '1-2',
    name: '1-2',
    // 不可选
    disabled: true,
    children: [
      {
        sid: '1-2-1',
        parentSid: '1-2',
        name: '1-2-1',
      },
      {
        sid: '1-2-2',
        parentSid: '1-2',
        name: '1-2-2',
        // 不可选
        disabled: true,
        children: [
          {
            sid: '1-2-2-1',
            parentSid: '1-2-2',
            name: '1-2-2-1',
          },
          {
            sid: '1-2-2-2',
            parentSid: '1-2-2',
            name: '1-2-2-2',
          },
        ],
      },
    ],
  },
]);

function formatTreeData(sourceList: any[]): TreeData {
  return (
    sourceList?.map((item) => {
      const { sid, parentSid, name, children, ...props } = item;
      return {
        key: sid,
        title: name,
        parentKey: parentSid,
        children: children ? formatTreeData(children) : undefined,
        ...props,
      };
    }) ?? []
  );
}

watch(selectedKeys, () => {
  // 打印选中的 checkedKeys 的所有祖先节点的 id (包含选中的节点本身)
  console.log(modelTreeRef.value?.getAllParentKeys());
});
</script>

<template>
  <ModelTree
    ref="modelTreeRef"
    v-model:selectedKeys="selectedKeys"
    v-model:expandedKeys="expandedKeys"
    showLine
    multiple
    :bordered="false"
    :checkable="false"
    :treeData="treeData"
    :formatTreeData="formatTreeData"
  />
</template>
<script setup lang="ts">
import { ModelTree } from '@/library';
import type { TreeData } from '@/library/ModelTree';
import { ref, watch, onMounted } from 'vue';
const selectedKeys = ref<string[]>([]);
const expandedKeys = ref<string[]>([]);
const modelTreeRef = ref<InstanceType<typeof ModelTree>>();

onMounted(() => {
  selectedKeys.value = ['1-1-1-1'];
  expandedKeys.value = ['1-1', '1-1-1'];
});

const treeData = ref([
  {
    sid: '1-1',
    title: '1-1',
    // 不可选
    disabled: true,
    children: [
      {
        sid: '1-1-1',
        parentSid: '1-1',
        name: '1-1-1',
        // 不可选
        disabled: true,
        children: [
          {
            sid: '1-1-1-1',
            parentSid: '1-1-1',
            name: '1-1-1-1',
          },
          {
            sid: '1-1-1-2',
            parentSid: '1-1-1',
            name: '1-1-1-2',
          },
        ],
      },
      {
        sid: '1-1-2',
        parentSid: '1-1',
        name: '1-1-2',
      },
      {
        sid: '1-1-3',
        parentSid: '1-1',
        name: '1-1-3',
      },
    ],
  },
  {
    sid: '1-2',
    name: '1-2',
    // 不可选
    disabled: true,
    children: [
      {
        sid: '1-2-1',
        parentSid: '1-2',
        name: '1-2-1',
      },
      {
        sid: '1-2-2',
        parentSid: '1-2',
        name: '1-2-2',
        // 不可选
        disabled: true,
        children: [
          {
            sid: '1-2-2-1',
            parentSid: '1-2-2',
            name: '1-2-2-1',
          },
          {
            sid: '1-2-2-2',
            parentSid: '1-2-2',
            name: '1-2-2-2',
          },
        ],
      },
    ],
  },
]);

function formatTreeData(sourceList: any[]): TreeData {
  return (
    sourceList?.map((item) => {
      const { sid, parentSid, name, children, ...props } = item;
      return {
        key: sid,
        title: name,
        parentKey: parentSid,
        children: children ? formatTreeData(children) : undefined,
        ...props,
      };
    }) ?? []
  );
}

watch(selectedKeys, () => {
  // 打印选中的 checkedKeys 的所有祖先节点的 id (包含选中的节点本身)
  console.log(modelTreeRef.value?.getAllParentKeys());
});
</script>

<template>
  <ModelTree
    ref="modelTreeRef"
    v-model:selectedKeys="selectedKeys"
    v-model:expandedKeys="expandedKeys"
    showLine
    multiple
    :bordered="false"
    :checkable="false"
    :treeData="treeData"
    :formatTreeData="formatTreeData"
  />
</template>

ModelTree API

propNamedescriptiontypedefault value
treeData数据源,数据在组件内部通过 props.computedTreeData 进行格式化转换成 Tree 需要的数据格式any[]-
bordered是否需要边框booleantrue
multiple是否可以多选booleanfalse
checkable节点前添加 Checkbox 复选框booleantrue
placeholder搜索输入框的 placeholderstring请输入关键字进行查找
showFilter是否展示搜索输入框booleanfalse
disabled是否禁用boolean-
checkedKeys(v-model)选中的keystring[],number[]-
expandedKeys(v-model)展开的keystring[],number[]-
fieldNames字段名称设置FieldNames-
formatTreeData将 treeData 转换成组件需要的数据格式,如果 treeData 本身就满足 TreeData 数据类型则不需要传递此属性function(treeData)-

Released under the MIT License.