# 递归组件

官方介绍:递归组件 (opens new window)

  组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name 选项来做这件事。

注意

  请确保递归调用是条件性的 (例如使用一个最终会得到 false 的 v-if),否则会导致“max stack size exceeded”错误(无限循环)

# 一、数据

# 1、扁平数据

  方便后端将数据存储到数据库中

let data = [
  {
    id: '51', // 区域 id
    name: '四川省', // 区域名字
    pid: '0' // 区域的父级区域 id
  },
  {
    id: '5101',
    name: '成都市',
    pid: '51' // 成都的父级是四川省,所以 pid 是 51
  }
  // ...
]

# 2、树形数据

  方便前端将数据展示到页面

let treeData = [
  {
    id: '51', // 地址 id
    name: '四川省', // 地址名
    pid: '0', // 该地址的父节点 id
    children: [
      {
        id: '5101',
        name: '成都市',
        pid: '51',
        children: [
          {
            id: '510101',
            name: '市辖区',
            pid: '5101',
            children: [] // 如果该区域节点没有子集,children 则为空数组!!!
          }
          // ...
        ]
      }
      // ...
    ]
  }
  // ...
]

# 二、开发应用

# 1、数据转换

function convertToTree(regions, rootId = '0') {
  // 方式1:使用forEach

  let childList = []

  regions.forEach((item) => {
    if (item.pid === rootId) {
      // 1、获取孩子节点A
      childList.push(item)

      // 2、将与A匹配的孩子节点添加到 item.children 上
      item.children = convertToTree(regions, item.id)
    }
  })

  return childList

  // // 方式2:使用filter

  // // 1、获取孩子节点A
  // let childList = regions.filter(item => item.pid === rootId)

  // // 2、将与A匹配的孩子节点添加到 item.children 上
  // childList.map(item => {
  //   return item.children = convertToTree(regions, item.id)
  // })

  // return childList
}

module.exports = convertToTree // 检测需要,请勿删除

# 2、递归组件

  当然类似的还有:

  下面以评论系统为例,写一个简单的案例:

树形结构数据
const comments = [
  {
    id: 1,
    text: 'First comment',
    replies: [
      {
        id: 2,
        text: 'Reply 1',
        replies: []
      },
      {
        id: 3,
        text: 'Reply 2',
        replies: [
          {
            id: 4,
            text: 'Nested reply',
            replies: []
          }
        ]
      }
    ]
  },
  {
    id: 5,
    text: 'Second comment',
    replies: []
  }
]
<template>
  <div>
    <Comment v-for="comment in comments" :key="comment.id" :comment="comment" />
  </div>
</template>

<script>
import Comment from './Comment.vue'

export default {
  name: 'App',
  components: {
    Comment
  },
  data() {
    return {
      comments: [
        // 数据结构
      ]
    }
  }
}
</script>
<!-- Comment.vue -->

<template>
  <div class="comment">
    <div class="comment-content">{{ comment.text }}</div>
    <div v-if="comment.replies && comment.replies.length > 0" class="comment-replies">
      <Comment v-for="reply in comment.replies" :key="reply.id" :comment="reply" />
    </div>
  </div>
</template>

<script>
export default {
  name: 'Comment',
  props: {
    comment: {
      type: Object,
      required: true
    }
  }
}
</script>
更新于 : 8/7/2024, 2:16:31 PM