Vue3递归组件

311 阅读1分钟

前言

Vue递归组件用于在组件内部调用自身,以实现树状结构或嵌套结构的渲染。

常见用途

  1. 树形菜单:可以递归渲染多级菜单项。
  2. 文件目录:适用于展示文件夹和文件的嵌套结构。
  3. 评论回复:用于显示具有嵌套回复的评论列表。
  4. 组织结构图:渲染公司或组织的层级关系。

示例预览

示例源码

tree.gif

示例代码

Parent.vue

<script setup lang="ts">
import ChildNode from './ChildNode.vue';

const treeData = [
  {
    "id": "1",
    "children": [
      {
        "id": "1-1",
        "children": [
          {
            "id": "1-1-1",
            "children": []
          }
        ]
      },
      {
        "id": "1-2",
        "children": []
      }
    ]
  },
  {
    "id": "2",
    "children": [
      {
        "id": "2-1",
        "children": []
      },
      {
        "id": "2-2",
        "children": []
      }
    ]
  }
]


</script>

<template>
  <ChildNode v-for="node in treeData" 
             :key="node.id"
             :level="1"
             :data="node"
             isVisible
   />
</template>

ChildNode.vue

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

type Data = {
  id: string
  children?: Data[]
}

defineProps<{
  level: number,
  data: Data
  isVisible: boolean
}>()


const isExpand = ref(true)

const chnageExpand = () => {
  isExpand.value = !isExpand.value
}
</script>

<template>
  <div class="tree-node" v-if="isVisible" >
    <span v-if="level > 1" :style="{ paddingLeft: (level - 1) * 25 + 'px' }"></span>
    <button class="expand-btn" v-if="data.children?.length" @click="chnageExpand">
      {{ isExpand ? '-' : '+' }}
    </button>
    <span class="expand-btn" v-else style="visibility: hidden;"></span>
    <div class="tree-node-cotent">
      {{ data.id }}
    </div>
  </div>
  <template v-if="data.children?.length">
    <ChildNode v-for="node in data.children" :key="node.id" :level="level + 1" :data="node" :isVisible="isVisible && isExpand" />
  </template>
</template>
<style>
.tree-node {
  display: flex;
  align-items: center;
}

.expand-btn {
  margin-right: 5px;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

.tree-node-cotent {
  border: 1px solid #ddd;
  padding: 5px;
  margin-bottom: 4px;
  flex-grow: 2;
}
</style>

总结

  • 一个单文件组件可以通过它的文件名其自己所引用
  • 递归组件的核心在于其自我调用能力,允许在数据结构不确定深度的情况下进行动态渲染