Skip to content

Tree 树形组件

用于展示层级数据结构,支持递归渲染、图标动画和展开/折叠功能。

基础用法

Tree 组件通过递归方式渲染多层级数据结构,每个节点都可以展开或折叠其子节点。

基础树形组件

Level one 1
Level one 2
Level one 3

<template>
    <div class="demo-container">
        <h3>基础树形组件</h3>
        <div class="tree-wrapper">
            <hy-tree v-for="node in treeData" :key="node.id" :node="node" @node-click="handleNodeClick" />
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const treeData = ref([
    {
        id: 1,
        label: 'Level one 1',
        children: [
            {
                id: 11,
                label: 'Level two 1-1',
                children: [
                    {
                        id: 111,
                        label: 'Level three 1-1-1'
                    }
                ]
            }
        ]
    },
    {
        id: 2,
        label: 'Level one 2',
        children: [
            {
                id: 21,
                label: 'Level two 2-1',
                children: []
            },
            {
                id: 22,
                label: 'Level two 2-2',
                children: []
            }
        ]
    },
    {
        id: 3,
        label: 'Level one 3',
        children: []
    }
])

const handleNodeClick = (node: any) => {
    console.log('点击了节点:', node)
}
</script>

<style scoped>
.demo-container {
    padding: 20px;
    border: 1px solid #e4e7ed;
    border-radius: 4px;
    background-color: #fff;
}

.tree-wrapper {
    margin-top: 10px;
}
</style>

节点点击事件

点击节点时会触发 node-click 事件,可以获取当前节点信息。

节点点击事件

当前点击的节点: 无

根目录

<template>
  <div class="demo-container">
    <h3>节点点击事件</h3>
    <div class="info-panel">
      <p>当前点击的节点: {{ (currentNode as any)?.label || '无' }}</p>
    </div>
    <div class="tree-wrapper">
      <hy-tree
        v-for="node in treeData"
        :key="node.id"
        :node="node"
        @node-click="handleNodeClick"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const currentNode = ref(null)

const treeData = ref([
  {
    id: 1,
    label: '根目录',
    children: [
      {
        id: 11,
        label: 'src',
        children: [
          {
            id: 111,
            label: 'main.js'
          },
          {
            id: 112,
            label: 'App.vue'
          }
        ]
      },
      {
        id: 12,
        label: 'public',
        children: [
          {
            id: 121,
            label: 'index.html'
          }
        ]
      }
    ]
  }
])

const handleNodeClick = (node: any) => {
  currentNode.value = node
  console.log('点击了节点:', node)
}
</script>

<style scoped>
.demo-container {
  padding: 20px;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  background-color: #fff;
}

.info-panel {
  padding: 10px;
  background-color: #f5f7fa;
  border-radius: 4px;
  margin-bottom: 10px;
}

.tree-wrapper {
  margin-top: 10px;
}
</style>

图标旋转动画

展开/折叠节点时,图标会平滑旋转 90 度,提供良好的视觉反馈。

图标旋转动画

点击节点查看图标旋转动画效果

📁 项目文件夹

<template>
    <div class="demo-container">
        <h3>图标旋转动画</h3>
        <p>点击节点查看图标旋转动画效果</p>
        <div class="tree-wrapper">
            <hy-tree v-for="node in treeData" :key="node.id" :node="node" @node-click="handleNodeClick" />
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const treeData = ref([
    {
        id: 1,
        label: '📁 项目文件夹',
        children: [
            {
                id: 11,
                label: '📂 src',
                children: [
                    {
                        id: 111,
                        label: '📄 main.js'
                    },
                    {
                        id: 112,
                        label: '📄 App.vue'
                    }
                ]
            },
            {
                id: 12,
                label: '📦 package.json',
                children: []
            }
        ]
    }
])

const handleNodeClick = (node: any) => {
    console.log('节点展开/折叠:', node.label)
}
</script>

<style scoped>
.demo-container {
    padding: 20px;
    border: 1px solid #e4e7ed;
    border-radius: 4px;
    background-color: #fff;
}

.tree-wrapper {
    margin-top: 10px;
}
</style>

展开/折叠动画

节点展开和折叠时具有平滑的过渡动画效果。

展开/折叠动画

观察节点展开和折叠时的平滑过渡效果

🏢 公司组织架构

<template>
    <div class="demo-container">
        <h3>展开/折叠动画</h3>
        <p>观察节点展开和折叠时的平滑过渡效果</p>
        <div class="tree-wrapper">
            <hy-tree v-for="node in treeData" :key="node.id" :node="node" @node-click="handleNodeClick" />
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const treeData = ref([
    {
        id: 1,
        label: '🏢 公司组织架构',
        children: [
            {
                id: 11,
                label: '👨‍💻 技术部',
                children: [
                    {
                        id: 111,
                        label: ' frontend 前端组'
                    },
                    {
                        id: 112,
                        label: ' backend 后端组'
                    }
                ]
            },
            {
                id: 12,
                label: '🎨 设计部',
                children: [
                    {
                        id: 121,
                        label: ' UI设计组'
                    },
                    {
                        id: 122,
                        label: ' UX研究组'
                    }
                ]
            }
        ]
    }
])

const handleNodeClick = (node: any) => {
    console.log('动画演示:', node.label)
}
</script>

<style scoped>
.demo-container {
    padding: 20px;
    border: 1px solid #e4e7ed;
    border-radius: 4px;
    background-color: #fff;
}

.tree-wrapper {
    margin-top: 10px;
}
</style>

Tree API

Props

NameDescriptionTypeDefault
node树节点数据对象,必须包含 id 和 label 属性object

TreeNode 数据结构

typescript
interface TreeNode {
  id: string | number
  label: string
  children?: TreeNode[]
  [key: string]: any
}