Skip to content

Tree 树形控件

基础用法

查看示例
vue
<script setup lang="ts">
import { ref } from 'vue'

const data = ref([
  {
    value: '选项1',
    key: '1',
    children: [
      {
        value: '选项1-1',
        key: '1-1',
      },
      {
        value: '选项1-2',
        key: '1-2',
        children: [
          {
            value: '选项1-2-1',
            key: '1-2-1',
          },
        ],
      },
    ],
  },
  {
    value: '选项2',
    key: '2',
    children: [
      {
        value: '选项2-1',
        key: '2-1',
      },
    ],
  },
])
</script>

<template>
  <yy-tree :data="data" />
</template>

属性重命名

查看示例
vue
<script setup lang="ts">
import { ref } from 'vue'

const data = ref([
  {
    anyValue: '选项1',
    anyKey: '1',
    children: [
      {
        anyValue: '选项1-1',
        anyKey: '1-1',
      },
      {
        anyValue: '选项1-2',
        anyKey: '1-2',
        children: [
          {
            anyValue: '选项1-2-1',
            anyKey: '1-2-1',
          },
        ],
      },
    ],
  },
  {
    anyValue: '选项2',
    anyKey: '2',
    children: [
      {
        anyValue: '选项2-1',
        anyKey: '2-1',
      },
    ],
  },
] as any[])
</script>

<template>
  <yy-tree :data="data" key-field="anyKey" value-field="anyValue" />
</template>

缩进宽度

查看示例
vue
<script setup lang="ts">
import { ref } from 'vue'

const data = ref([
  {
    value: '选项1',
    key: '1',
    children: [
      {
        value: '选项1-1',
        key: '1-1',
      },
      {
        value: '选项1-2',
        key: '1-2',
        children: [
          {
            value: '选项1-2-1',
            key: '1-2-1',
          },
        ],
      },
    ],
  },
  {
    value: '选项2',
    key: '2',
    children: [
      {
        value: '选项2-1',
        key: '2-1',
      },
    ],
  },
])
</script>

<template>
  <yy-tree :data="data" :indent-width="42" />
</template>

默认展开

查看示例
vue
<script setup lang="ts">
import { ref } from 'vue'
import { createData } from './utils'

const data1 = ref<any[]>([])
data1.value.push(...(createData(3, 3) as any[]))

const expandedKeys = ref(['0', '0-0'])
</script>

<template>
  <yy-tree :data="data1" :default-expanded-keys="expandedKeys" />
</template>

可选择

查看示例
vue
<script setup lang="ts">
import { ref } from 'vue'

const data = ref([
  {
    value: '选项1',
    key: '1',
    children: [
      {
        value: '选项1-1',
        key: '1-1',
      },
      {
        value: '选项1-2',
        key: '1-2',
        children: [
          {
            value: '选项1-2-1',
            key: '1-2-1',
          },
        ],
      },
    ],
  },
  {
    value: '选项2',
    key: '2',
    children: [
      {
        value: '选项2-1',
        key: '2-1',
      },
    ],
  },
])

const selectedKeys = ref(['1'])
</script>

<template>
  <yy-flex vertical>
    <yy-p>单选模式:</yy-p>
    <yy-tree v-model:selected-keys="selectedKeys" :data="data" selectable />

    <yy-p>多选模式:</yy-p>
    <yy-tree :data="data" selectable multiple />
  </yy-flex>
</template>

可拖拽

查看示例
vue
<script setup lang="ts">
import type { TreeOption } from '@yy-craft/components/tree'
import { getChildren } from '@yy-craft/components/tree/src/utils'
import { ref } from 'vue'

const data = ref([
  {
    value: '选项1',
    key: '1',
    children: [
      {
        value: '选项1-1',
        key: '1-1',
      },
      {
        value: '选项1-2',
        key: '1-2',
        children: [
          {
            value: '选项1-2-1',
            key: '1-2-1',
          },
        ],
      },
    ],
  },
  {
    value: '选项2',
    key: '2',
    children: [
      {
        value: '选项2-1',
        key: '2-1',
      },
    ],
  },
] as TreeOption[])

function onDrag(value: {
  dragNode: TreeOption
  dragNodeParent: TreeOption | null
  dropNode: TreeOption | null
  position: number
}) {
  const { dragNode, dragNodeParent, dropNode, position } = value

  // *切记先添加再删除
  const dropNodePool = getChildren(data.value, dropNode)
  const dragNodePool = getChildren(data.value, dragNodeParent)

  if (dropNodePool === dragNodePool) {
    // 同数组操作
    const index = dragNodePool.findIndex(item => item.key === dragNode.key)
    if (position - 1 === index)
      return
    dropNodePool.splice(position, 0, dragNode)
    dropNodePool.splice(position - 1 > index ? index : index + 1, 1)
  }
  else {
    dropNodePool.splice(position, 0, dragNode)
    const index = dragNodePool.findIndex(item => item.key === dragNode.key)
    dragNodePool.splice(index, 1)
  }

  data.value = [...data.value]
}
</script>

<template>
  <yy-tree :data="data" draggable @drag="onDrag" />
</template>

动态加载

查看示例
vue
<script setup lang="ts">
import type { TreeOption } from '@yy-craft/components/tree'
import { ref } from 'vue'

const data = ref([
  {
    value: '根节点',
    key: '0',
    isLeaf: false,
  },
] as TreeOption[])

function onLoad(node: TreeOption) {
  return new Promise<void>((resolve) => {
    setTimeout(() => {
      const children = [
        {
          value: `节点 ${node.key}-0`,
          key: `${node.key}-0`,
          isLeaf: false,
        },
        {
          value: `节点 ${node.key}-1`,
          key: `${node.key}-1`,
          isLeaf: false,
        },
      ] as any[]
      node.children = children
      resolve()
    }, 1000)
  })
}
</script>

<template>
  <yy-tree :data="data" :on-load="onLoad" />
</template>

虚拟滚动

查看示例
vue
<script setup lang="ts">
import { ref } from 'vue'
import { createData } from './utils'

// 生成大量数据
const data = ref(createData(3, 10)!)

const defaultExpandedKeys = ref([] as string[])

function add(prefix?: string) {
  for (let i = 0; i < 10; i++) {
    defaultExpandedKeys.value.push(`${prefix ? `${prefix}-` : ''}${i}`)
    if (!prefix) {
      add(`${i}`)
    }
  }
}

add()
</script>

<template>
  <yy-tree
    :data="data"
    virtual-scroll
    :default-expanded-keys="defaultExpandedKeys"
    :virtual-list-props="{ wrapperMaxSize: 300 }"
  />
</template>

传递插槽

查看示例
vue
<script setup lang="ts">
import { ref } from 'vue'

const data = ref([
  {
    value: '选项1',
    key: '1',
    children: [
      {
        value: '选项1-1',
        key: '1-1',
      },
      {
        value: '选项1-2',
        key: '1-2',
        children: [
          {
            value: '选项1-2-1',
            key: '1-2-1',
          },
        ],
      },
    ],
  },
  {
    value: '选项2',
    key: '2',
    children: [
      {
        value: '选项2-1',
        key: '2-1',
      },
    ],
  },
])
</script>

<template>
  <yy-tree :data="data">
    <template #default="{ node }">
      <div>我是自定义的内容 {{ node.key }}</div>
    </template>
  </yy-tree>
</template>

Props

参数说明类型默认值
data展示数据TreeOption[]-
valueField节点值的字段名string'value'
keyField节点键的字段名string'key'
defaultExpandedKeys默认展开的节点string[]-
onLoad加载子节点的函数(node: TreeOption) => Promise<any>-
selectable是否可选择booleanfalse
multiple是否可多选booleanfalse
selectedKeys选中的节点string[]-
indentWidth缩进宽度number21
draggable是否可拖拽booleanfalse
virtualScroll是否启用虚拟滚动booleanfalse
virtualListProps虚拟列表配置{ wrapperMaxSize?: number }-
scrollbarProps滚动条配置: 仅在虚拟滚动时生效ScrollbarProps-

Events

事件名说明回调参数
drag拖拽完成时触发(info: { dragNode: TreeOption, dragNodeParent: TreeOption | null, dropNode: TreeOption | null, position: number }) => void

TreeOption 数据结构

ts
interface TreeOption {
  value: string | number // 节点值
  key: string // 节点唯一标识
  children?: TreeOption[] // 子节点
  isLeaf?: boolean // 是否是叶子节点
  [key: string]: any // 其他自定义属性
}