关于前端:Vue的递归组件渲染嵌套评论

34次阅读

共计 4440 个字符,预计需要花费 12 分钟才能阅读完成。

新出了一个系列:Vue2 与 Vue3 技巧小册

微信搜寻【大迁世界】, 我会第一工夫和你分享前端行业趋势,学习路径等等。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

大多数古代社交网络都包含一个性能,用户能够通过对该特定评论的评论来回复评论。如果咱们将其可视化,咱们的评论的数据会像上面的构造:

- Comment A
                - comment a1
                                - comment a12
                - comment a2
- Comment B
- Comment C

Comment A 有子评论 comment a1comment a2。反过来,comment a1 有子评论comment a12,它也能够有本人的子评论。

有了这种构造,咱们能够让一个正文有有数层的子正文。你可能曾经相熟了这种结构化数据的办法,也就是所谓的树状构造。不了解的能够想想电脑上的目录,一个文件夹能够有子文件夹等等。

这节课,咱们来看看在 Vue 中如何应用递归组件来治理树状构造的数据。在介绍 Vue 中递归组件之前,咱们先回顾一下什么是递归。

什么是递归

递归简略的说就是本人调用本人,思考上面这个函数:

function sum_numbers(arr, n) {return sum_numbers(arr, n - 1) + arr[n - 1];
}

尽管有些缺点的,但下面的函数能够被认为是递归函数,因为它在函数中调用了本人。然而,这个定义并不包含所有的内容。递归是一种解决问题的办法。它基于这样一个前提:给定一个问题,如果咱们晓得其子问题的解决方案,咱们就能够找到其解决方案。

例如,下面的 sum_numbers 函数能够找到一个给定数组 arr = [1, 2, 3, 4, 5] 中所有数字的总和。在求和问题中,如果咱们晓得 5 之前的所有数字之和,那么咱们能够将问题简化为 arr 中的数字之和等于 最初一个元素和最初一个元素之前所有数字之和

在下面定义的 sum_numbers 函数中,表达式 return sum_numbers(arr, n - 1) + arr[n - 1]; 所做的正是咱们方才形容的。

为了 描述 sum_numbers 函数在输出 [1, 2, 3, 4] 的状况下如何从头到尾执行,请看上面的代码:

**sum_numbers([1, 2, 3, 4], 4)
    |
        calls
                |**
**sum_numbers([1, 2, 3], 3) + 4
    |
        calls
                |
sum_numbers([1, 2], 2) + 3
                |
        calls
                |
sum_numbers([1], 1) + 2
                |
        calls
                |
sum_numbers([], 0) + 1 --** 这里有一个问题

这里有一个问:;咱们的递归函数试图将一个空列表增加到一个数字中。事实上,更大的问题是,咱们的递归函数会始终有限地调用本人。

为了确保咱们的递归函数不会有限地调用本人,咱们须要一个根本状况。你能够把基数看作是咱们心愿咱们的函数进行自我调用的点。

在下面例子中,如果 sum_numbers 函数中只有一个数字,它就应该进行调用本人。如果数组中只剩下一个数字,那么就没有什么能够与之相加的了,在这种状况下,咱们只需返回这个数字。

function sum_numbers(arr, n) {if(n <= 1){ //Base Case
    return arr[0];
  } else {return sum_numbers(arr, n - 1) + arr[n - 1];
  }
}

从根本上说,这就是递归的意义,但与 Vue 的递归组件有什么分割?

Vue 递归组件

Vue 中的组件是可重用的 Vue 实例。大多数时候,当咱们在 Vue 中创立一个组件时,只是为了能在其余中央重用它。例如,一个电子商务网站,咱们能够在多个页面上显示产品。也能够有一个Product Component,能够在不同的页面上出现,而不是在每个须要的页面上反复 Product Component 的代码。

如果一个 Vue 组件在本人的模板中援用本人,那么它就被认为是递归的。递归组件与一般组件不同。除了在其余中央被重用之外,递归组件还在其模板中援用本人。

为什么一个组件会援用本人?当你在其余组件中渲染一个组件时,客体组件是子体,而渲染它的组件是父体。

Product Component 的例子中,该组件能够将 ProductReview 作为其子组件。在这种状况下,咱们对这些组件所代表的实体有两个不同的组件是有意义的,因为产品和评论在各方面都是不同的。

然而,如果咱们以 CommentSub-comment 为例,那么就不一样了。这两个组成部分代表的是同一件事。一个子评论也是一个评论。因而,咱们为 CommentSub-comment 设置两个不同的组件是没有意义的,因为它们在结构上是一样的。咱们能够只有一个援用本人的 Comment 组件。还是太形象了?看上面的片段:

<template>
  <li class="comment">
    <span>{{comment.comment}}</span>
    <comment v-for="reply in comment.replies" :comment="reply"></comment>
  </li>
</template&gt;

<script>
export default {
  name: "comment",
  props: {comment: Object}
};
</script>

尽管,但下面的组件能够被认为是递归的,因为它援用了本人。和递归函数一样,递归组件也必须有一个终止条件,而下面的代码中短少这个终止条件。这里须要留神的另一件重要的事件是,为了使一个组件可能援用本人,必须定义 name 选项。

当初明确了什么是 Vue 中的递归组件,接着,来看看如何应用它来构建一个嵌套的评论界面。

构建评论界面

设置 Vue 开发环境

首先,初始化一个新的 Vue 我的项目,在终端运行 vue create nested-comments命令:

vue create nested-comments

依据提醒装置后,会失去如下的目录构造:

应用 vue serve 把我的项目跑起来。

用递归组件来渲染嵌套的评论

为了将 嵌套评论渲染到 DOM,首先,删除 src/viewssrc/components中的所有文件。而后,创立 src/components/Comment.vuescript 内容如下:

<script>
export default {
  name: "recursive-comment",
  props: {
    comment: {
      type: String,
      required: true,
    },
    replies: {
      type: Array,
      default: () => [],
    },
  },
};
</script>

在下面的代码片断中,将的组件命名为递归组件(recursive-component)。记住,在 Vue 中,一个递归组件必须有一个申明的 name。此外,咱们的组件心愿在它被援用的任何中央都能将commentrepliesprops 传递给它。

接着,template 内容如下:

<template>
  <li>
    <span class="comment">{{comment}}</span>
    <ul class="replies" v-if="replies.length">
      <div v-for="(item, index) in replies" :key="index">
        <recursive-comment
          v-bind="{
            comment: item.comment,
            replies: item.replies,
          }"
        />
      </div>
    </ul>
  </li>
</template>

recursive-comment 组件在本人的模板中援用本人。v-if="replies.length" 是终于递归的条件,一旦条件不成立,则进行递归。

接下来,在 App.vue 援用一下就行啦:

<template>
  <ul v-for="(item, index) in comments" :key="index" class="comments">
    <Comment
      v-bind="{
        comment: item.comment,
        replies: item.replies,
      }"
    />
  </ul>
</template>

<script>
import Comment from "@/components/Comment";

export default {data: () => ({
    comments: [
      {
        comment: "First comment",
        replies: [
          {
            comment: "sub-comment 1 for comment 1",
            replies: [
              {
                comment: "sub-sub-comment 1",
                replies: [
                  {comment: "sub-sub-sub-comment 1",},
                  {comment: "sub-sub-sub-comment 2"},
                ],
              },
              {comment: "sub-sub-comment 2"},
            ],
          },
          {comment: "sub-comment 2 for comment 1"},
        ],
      },

      {
        comment: "Second comment",
        replies: [
          {
            comment: "sub-comment 1 for comment 2",
            replies: [{ comment: "sub-sub-comment 1"},
              {comment: "sub-sub-comment 2"},
            ],
          },
          {comment: "sub-comment 2 for comment 2"},
        ],
      },
    ],
  }),

  components: {Comment,},
};
</script>

<style>
.comments ul {
  padding-left: 16px;
  margin: 6px 0;
}
</style>

运行,成果如下所示:

总结

尽管咱们举的例子不是一个典型的评论组件,但咱们的指标是摸索如何利用 Vue 中递归组件的力量来渲染嵌套数据。

咱们看到,咱们能够通过创立一个在本人的模板中援用本人的组件来做到这一点。这种递归办法在渲染那些看似不同但构造雷同的数据实体时特地有用。例如,以咱们的 commentsreplies 为例。

乍一看,咱们如同须要两个组件,一个用于comments,另一个用于 replies。然而,用递归的办法,咱们可能用一个组件来渲染这两种内容。最重要的是,咱们的组件会渲染所有的评论和回复,直到它达到终止条件。

编辑中可能存在的 bug 没法实时晓得,预先为了解决这些 bug, 花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。

作者:Nyior Clement 译者:前端小智 起源:logrocket

原文:https://blog.logrocket.com/au…

交换

有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

正文完
 0