Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何使用Vue中的嵌套插槽(包括作用域插槽) #232

Open
husky-dot opened this issue May 25, 2020 · 0 comments
Open

如何使用Vue中的嵌套插槽(包括作用域插槽) #232

husky-dot opened this issue May 25, 2020 · 0 comments

Comments

@husky-dot
Copy link
Owner

作者:Michael Thiessen
译者:前端小智
来源:medium

点赞再看,养成习惯

本文 GitHub https://github.com/qq449245884/xiaozhi 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。

最近我弄清楚了如何递归地实现嵌套插槽,包括如何使用作用域插槽来实现。起因是我想看看是否可以构建一个复制v-for指令但仅使用template组件。

它还支持插槽和作用域插槽,也可以支持命名插槽,我们可以这样使用它:

<template>
  <div>
    <!-- Regular list -->
    <v-for :list="list" />
    
    <!-- List with bolded items -->
    <v-for :list="list">
      <template v-slot="{ item }">
        <strong>{{ item }}</strong>
      </template>
    </v-for>
  </div>
</template>

第一个将正常打印列表,而第二个将每个项包装在<strong>标记中。

这不是一个非常有用的组件,但可以从中学到的最多,我们来看看。

无循环实现循环

通常,当我们要渲染元素或组件的列表时,可以使用v-for指令,但这次我们希望完全摆脱它。

那么,我们如何在不使用循环的情况下渲染项目列表呢?就是使用 递归

我们可以使用递归来渲染项目列表。过程并不会复杂,我们来看看怎么做。

递归表示一个列表

我在大学里最喜欢的课程之一是“编程语言概念”

对我来说,最有趣的部分是探索函数式编程和逻辑编程,并了解与命令式编程的区别(Javascript 和最流行的语言是命令式编程)。

这门课让我真正了解如何使用递归,因为在纯函数语言中,一切都是递归。不管怎样,从那门课我学到了可以使用递归地表示一个列表。

与使用数组不同,每个列表是一个值(头)和另一个列表(尾)。

[head, tail]

例如要表示列表[1、2、3],则可以递归方式表示为:

[1, [2, [3, null]]]

我们必须以某种方式结束列表,因此我们使用null而不是另一个数组(也可以使用空数组)。

看到这里,你或许就可以明白了,我们可以使用此概念并将其应用于我们的组件。 相反,我们将递归嵌套组件以表示列表。

我们最终将渲染出这样的内容。 注意我们“list”的嵌套结构:

<div>
  1
  <div>
    2
    <div>
      3
    </div>
  </div>
</div>

诚然,这与v-for渲染的效果并不完全相同,但这也不是本练习的重点。

构建组件

首先,我们将解决递归渲染项目列表的问题。

使用递归来渲染列表

这次我们使用一个普通数组,而不是使用前面介绍的递归列表:

[1, 2, 3]

这里要讨论两种情况:

  • 基本情形-渲染列表中的第一项
  • 递归情形-渲染项目,然后沉浸下一个列表

我们把[1,2,3]传给v-for

<template>
  <v-for :list="[1, 2, 3]" />
</template>

我们希望获取列表中的第一项,即1,并显示它

<template>
  <div>
    {{ list[0] }}
  </div>
</template>

现在,该组件将渲染1,就像我们期望的那样。

但是我们不能只渲染第一个值并停止。 我们需要渲染值,然后还渲染列表的其余部分:

<template>
  <div>
    {{ list[0] }}
    <v-for :list="list.slice(1)" />
  </div>
</template>

我们不传递整个list数组,而是删除第一项并传递新数组。第一个项目我们已经打印出来了,所以没有必要保留它。

顺序是这样的:

  1. 我们将[1,2,3]传递到v-for中进行渲染
  2. 我们的v-for组件渲染1,然后将[2,3]传递到下一个v-for进行渲染
  3. [2,3]并渲染2,然后将[3]传递到下一个v-for
  4. 最后一个v-for组件渲染出3,我们已经打印出列表!

现在,我们的Vue应用程序的结构如下所示:

<App>
  <v-for>
    <v-for>
      <v-for />
    </v-for>
  </v-for>
</App>

可以看到,我们有几个v-for组件,它们彼此嵌套在一起。最后一件事,我们需要停止递归

<template>
  <div>
    {{ list[0] }}
    <v-for
      v-if="list.length > 1"
      :list="list.slice(1)"
    />
  </div>
</template>

最终,渲染完所有项后,我们需要停止递归操作。

递归嵌套的插槽

现在,组件可以正常工作,但是我们也希望它与作用域内插槽一起使用,因为这样可以自定义渲染每个项的方式:

<template>
  <v-for :list="list">
    <template v-slot="{ item }">
      <strong>{{ item }}</strong>
    </template>
  </v-for>
</template>

嵌套插槽

一旦弄清楚了如何递归地嵌套插槽,就会对它痴迷一样的感叹:

  • 嵌套n级的插槽
  • 递归插槽
  • 包装组件将一个插槽转换为多个插槽

首先,我们将简要介绍嵌套插槽的工作方式,然后介绍如何将它们合并到v-for组件中。

假设我们有三个组件:ParentChildGrandchild。我们希望传递来自Parent组件的一些内容,并在Grandchild组件中渲染它。

Parent开始,我们传递一些内容:

// Parent.vue
<template>
  <Child>
    <span>Never gonna give you up</span>
  </Child>
</template>

我们在Child组件中做一些事情,将在稍后介绍。 然后我们的Grandchild组件获取插槽并渲染内容:

// Grandchild.vue
<template>
  <div>
    <slot />
  </div>
</template>

那么,这个Child组件是什么样的?

我们需要它从Parent组件获取内容并将其提供给Grandchild组件,因此我们将两个不同的插槽连接在一起。

// Child.vue
<template>
  <Grandchild>
    <slot />
  </Grandchild>
</template>

请记住,<slot />元素渲染出作为插槽传递到组件的内容。 因此,我们将从“Parent”中获取该内容,然后将其渲染到“Grandchild”插槽中。

添加作用域插槽

与嵌套作用域插槽唯一不同的是,我们还必须传递作用域数据。将其添加到v-for中,我们现在得到以下信息:

<template>
  <div>
    <slot v-bind:item="list[0]">
      <!-- Default -->
      {{ list[0] }}
    </slot>
    <v-for
      v-if="list.length > 1"
      :list="list.slice(1)"
    >
      <!-- Recursively pass down scoped slot -->
      <template v-slot="{ item }">
        <slot v-bind:item="item" />
      </template>
    </v-for>
  </div>
</template>

首先让我们看一下基本情况。

如果没有提供插槽,则默认<slot>元素内部的内容,并像以前一样渲染list[0]。 但是如果我们提供了一个slot,它会将其渲染出来,并通过slot作用域将列表项传递给父组件。

这里的递归情况类似。 如果我们将插槽传递给v-for,它将在下一个v-for的插槽中进行渲染,因此我们得到了嵌套。 它还从作用域槽中获取item并将其传递回链。

现在,我们这个组件仅使用template就能实现 v-for效果。

总结

我们做了很多事情,终于了解了如何创建一个仅使用 template 就能实现v-for的效果。

本文主要内容:

  • 递归地表示列表
  • 递归组件
  • 嵌套槽和嵌套作用域槽

原文:https://stackoverflow.com/questions/53430731/vuejs-nested-slots-how-to-pass-slot-to-grandchild

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug


交流

文章每周持续更新,可以微信搜索「 大迁世界 」第一时间阅读和催更(比博客早一到两篇哟),本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,整理了很多我的文档,欢迎Star和完善,大家面试可以参照考点复习,另外关注公众号,后台回复福利,即可看到福利,你懂的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant