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

更新日期: 2020-03-26阅读: 1.9k标签: 插槽

最近我弄清楚了如何递归地实现嵌套插槽,包括如何使用作用域插槽来实现。起因是我想看看是否可以构建一个复制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组件中。

假设我们有三个组件:Parent、Child和Grandchild。我们希望传递来自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/
作者:Michael Thiessen
译者:前端小智


链接: https://fly63.com/article/detial/9138

Vue 技能进阶:使用设计模式写出优雅的前端代码

本文针对 Vue 中如何控制组件子树之外的东西,探讨了四种解决方案,并展示了每种解决方案的优缺点。希望读者能从中受到启发。问你个问题,以前你可能从来没想过:有没有办法从子组件填充父组件插槽?

vue插槽slot和slot-scope

插槽我对他的理解就是父组件的东西插到子组件的<slot></slot>里面,也不知道这样理解对不对,方便自己记忆;作用域插槽我对他的理解就是数据在子组件里面,父组件可以用

一个案例搞懂 Vue.js 的作用域插槽

作用域插槽是 Vue.js 中一个很有用的特性,可以显著提高组件的通用性和可复用性。问题在于,它实在不太好理解。尝试搞清楚父子作用域之间错综复杂的关系,其痛苦程度不亚于求解一个棘手的数学方程。

Vue.js 中的无渲染行为插槽

在本文中我们讨论 Vue 中的无渲染插槽模式能够帮助解决哪些问题。在 Vue.js 2.3.0 中引入的作用域插槽显著提高了组件的可重用性。无渲染组件模式应运而生,解决了提供可重用行为和可插入表示的问题。

vue具名插槽、作用域插槽的新写法

有时让插槽内容能够访问子组件中才有的数据是很有用的。但是由于子组件的作用域在子组件,而父组件的作用域在父组件,这样一来,父组件就访问不到子组件的信息了,但是我们又不想用$emit发送事件去传递信息

深入了解Vue.js的作用域插槽

作用域槽是Vue.js的一个有用特性,它可以使组件更加通用和可重用。唯一的问题是它们很难理解!试着让你的头在父母和孩子的范围内交织,就像解决一个棘手的数学方程。

Vue 2.60 中, 插槽新增的v-slot

注意v-slot只能添加在<template>上(只有一种例外情况),这一点和已经废弃的slotattribute不同。有时让插槽内容能够访问子组件中才有的数据是很有用的。例如,设想一个带有如下模板的<current-user>组件:

如何通过带有Vue插槽的组件传递HTML内容

这篇文章将向您介绍如何使用Vue插槽在Vue.js中将数据从父组件传递到子组件。这篇文章适合所有阶段的开发人员(包括初学者)。

在Vue中,如何从插槽中发出数据

我们知道使用作用域插槽可以将数据传递到插槽中,但是如何从插槽传回来呢?将一个方法传递到我们的插槽中,然后在插槽中调用该方法。 我信无法发出事件

vue中插槽slot的使用

官方解释:Vue 实现了一套内容分发的 API,将 <slot> 元素作为承载分发内容的出口。插槽就是子组件中的提供给父组件使用的一个占位符

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!