vue3递归组件---树形组件

第一种方式,直接自己调用自己

Tree.vue

复制代码
<template>
  <div class="tree">
    <div v-for="(item, index) in data" :key="item.name">
      每一层 {{ item.name }}
      <Tree v-if="item?.children?.length" :data='item.children' />
    </div>
  </div>
</template>

<script setup lang="ts">
//递归的第一种方式 直接引入自己
import Tree from './Tree.vue'
import { TreeList } from '../ts/type'
type Props = {
  data?: TreeList[]
}
defineProps<Props>();
</script>

<style scoped>
.tree {
  margin-left: 20px;
  border-left: 2px #01847f dashed;
}
</style>

App.vue 里模拟树形数据,使用递归组件

复制代码
<template>
  <div>
    <Tree :data='data'/>
  </div>
</template>

<script setup lang="ts">
import Tree from './components/Tree.vue'
import { reactive } from 'vue'
import {TreeList } from './ts/type'
const data = reactive<TreeList[]>([
  {
    name: 'no.1',
    children: [
      {
        name: 'no.1-1',
        children: [
          {
            name: 'no.1-1-1',
            children:[]
          }
        ]
      },
    ],
  }, {
    name:'no.2'
  }, {
    name: 'no.3',
    children: [{
      name:'no.3-1'
    }]
  }

])
</script>

<style scoped></style>

type.ts 属性数据的结构

复制代码
export type TreeList = {
  name: string //名称
  icon?: string //图标可有可无
  children?: TreeList[] | [] //子节点 可有可无 还可能传空数组
}

第二种方式,export 一个name出去

第二种方式 就是像vue2 一样 export一个name出去

但是setup 语法糖下没办法使用 export

我们只需要再定义一个script标签就可以了

复制代码
<template>
  <div class="tree">
    <div v-for="(item, index) in data" :key="item.name">
      每一层 {{ item.name }}
      <Tree v-if="item?.children?.length" :data='item.children' />
    </div>
  </div>
</template>

<script setup lang="ts">
import { TreeList } from '../ts/type'
type Props = {
  data?: TreeList[]
}
defineProps<Props>();
</script>
<!-- 
  第二种方式 就是像vue2 一样 export一个name出去
  但是setup 语法糖下没办法使用 export 
  我们只需要再定义一个script标签就可以了
 -->
<script lang="ts">
export default {
  name:'Tree'
}
</script>

<style scoped>
.tree {
  margin-left: 20px;
  border-left: 2px #01847f dashed;
}
</style>

效果图

我们还可以给树形递归的组件添加参数传递事件

要注意在树形组件的里层也得添加自定义事件

并且这个自定义事件传的函数很有讲究

Tree.vue

复制代码
<template>
  <div class="tree">
    <div @click.stop="clickTreeItem(item)" v-for="(item, index) in data" :key="item.name">
      每一层 {{ item.name }}
      <Tree  @get-tree-item="clickTreeItem" v-if="item?.children?.length" :data='item.children' />
        <!-- Tree 组件不添加这个自定义事件的话  那么就只有最外层的根节点会向外传递数据 -->
      <!-- 注意此处派发的函数clickTreeItem没有传item参数了如果传了就相当于给树形组件(递归组件)的上级派发信息 没办法从外部拿到子节点所传递的数据了 -->
           <!--   @get-tree-item="clickTreeItem(item)"  写成这种形式的话  递归组件会依次向上层传递事件   -->
      <!-- 不传item的执行结果如下 -->
      <!--子组件派发的item Proxy {name: 'no.1-1-1', children: Array(0)}
          子组件派发的item Proxy {name: 'no.1-1-1', children: Array(0)}
          子组件派发的item Proxy {name: 'no.1-1-1', children: Array(0)}
          父组件得到的item Proxy {name: 'no.1-1-1', children: Array(0)} -->
      <!-- 传item的执行的结果如下 -->
      <!-- 子组件派发的item Proxy {name: 'no.1-1-1', children: Array(0)}
           子组件派发的item Proxy {name: 'no.1-1', children: Array(1)}
           子组件派发的item Proxy {name: 'no.1', children: Array(1)}
           父组件得到的item Proxy {name: 'no.1', children: Array(1)} -->
    </div>
  </div>
</template>

<script setup lang="ts">
import { TreeList } from '../ts/type'
type Props = {
  data?: TreeList[]
}
defineProps<Props>();

const emit =   defineEmits(['getTreeItem'])
const clickTreeItem=(item:TreeList)=>{
  console.log('子组件派发的item', item)
  emit('getTreeItem',item)
}
</script>
<!-- 
  第二种方式 就是像vue2 一样 export一个name出去
  但是setup 语法糖下没办法使用 export 
  我们只需要再定义一个script标签就可以了
 -->
<script lang="ts">
export default {
  name:'Tree'
}
</script>

<style scoped>
.tree {
  margin-left: 20px;
  border-left: 2px #01847f dashed;
}
</style>

App.vue

复制代码
<template>
  <div>
    <Tree :data='data' @get-tree-item="getTreeItem"/>
  </div>
</template>

<script setup lang="ts">
import Tree from './components/Tree.vue'
import { reactive } from 'vue'
import {TreeList } from './ts/type'
const data = reactive<TreeList[]>([
  {
    name: 'no.1',
    children: [
      {
        name: 'no.1-1',
        children: [
          {
            name: 'no.1-1-1',
            children:[]
          }
        ]
      },
    ],
  }, {
    name:'no.2'
  }, {
    name: 'no.3',
    children: [{
      name:'no.3-1'
    }]
  }

])

const getTreeItem = (item:TreeList) => {
  console.log('父组件得到的item',item)
}
</script>

<style scoped></style>
相关推荐
leobertlan3 小时前
2025年终总结
前端·后端·程序员
子兮曰3 小时前
OpenClaw架构揭秘:178k stars的个人AI助手如何用Gateway模式统一控制12+通讯频道
前端·javascript·github
Howrun7774 小时前
VSCode烦人的远程交互UI讲解
ide·vue.js·vscode
百锦再4 小时前
Reactive编程入门:Project Reactor 深度指南
前端·javascript·python·react.js·django·前端框架·reactjs
莲华君4 小时前
React快速上手:从零到项目实战
前端·reactjs教程
百锦再4 小时前
React编程高级主题:测试代码
android·前端·javascript·react.js·前端框架·reactjs
易安说AI4 小时前
Ralph Loop 让Claude无止尽干活的牛马...
前端·后端
颜酱5 小时前
图结构完全解析:从基础概念到遍历实现
javascript·后端·算法
失忆爆表症6 小时前
05_UI 组件库集成指南:Shadcn/ui + Tailwind CSS v4
前端·css·ui
小迷糊的学习记录6 小时前
Vuex 与 pinia
前端·javascript·vue.js