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

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

本文转载自微信公众号「大迁世界」,转载本文请联系大迁世界公众号。

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

[[327520]]

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

  1. <template> 
  2.   <div> 
  3.     <!-- Regular list --> 
  4.     <v-for :list="list" /> 
  5.  
  6.     <!-- List with bolded items --> 
  7.     <v-for :list="list"> 
  8.       <template v-slot="{ item }"> 
  9.         <strong>{{ item }}</strong> 
  10.       </template> 
  11.     </v-for> 
  12.   </div> 
  13. </template> 

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

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

无循环实现循环

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

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

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

递归表示一个列表

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

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

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

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

  1. [head, tail] 

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

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

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

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

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

  1. <div> 
  2.   1 
  3.   <div> 
  4.     2 
  5.     <div> 
  6.       3 
  7.     </div> 
  8.   </div> 
  9. </div> 

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

构建组件

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

(1) 使用递归来渲染列表

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

  1. [1, 2, 3] 

这里要讨论两种情况:

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

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

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

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

  1. <template> 
  2.   <div> 
  3.     {{ list[0] }} 
  4.   </div> 
  5. </template> 

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

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

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

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

顺序是这样的:

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

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

  1. <App> 
  2.   <v-for> 
  3.     <v-for> 
  4.       <v-for /> 
  5.     </v-for> 
  6.   </v-for> 
  7. </App> 

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

  1. <template> 
  2.   <div> 
  3.     {{ list[0] }} 
  4.     <v-for 
  5.       v-if="list.length > 1" 
  6.       :list="list.slice(1)" 
  7.     /> 
  8.   </div> 
  9. </template> 

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

(2) 递归嵌套的插槽

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

  1. <template> 
  2.   <v-for :list="list"> 
  3.     <template v-slot="{ item }"> 
  4.       <strong>{{ item }}</strong> 
  5.     </template> 
  6.   </v-for> 
  7. </template> 

(3) 嵌套插槽

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

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

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

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

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

  1. // Parent.vue 
  2. <template> 
  3.   <Child> 
  4.     <span>Never gonna give you up</span> 
  5.   </Child> 
  6. </template> 

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

  1. // Grandchild.vue 
  2. <template> 
  3.   <div> 
  4.     <slot /> 
  5.   </div> 
  6. </template> 

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

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

  1. // Child.vue 
  2. <template> 
  3.   <Grandchild> 
  4.     <slot /> 
  5.   </Grandchild> 
  6. </template> 

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

(4) 添加作用域插槽

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

  1. <template> 
  2.   <div> 
  3.     <slot v-bind:item="list[0]"> 
  4.       <!-- Default --> 
  5.       {{ list[0] }} 
  6.     </slot> 
  7.     <v-for 
  8.       v-if="list.length > 1" 
  9.       :list="list.slice(1)" 
  10.     > 
  11.       <!-- Recursively pass down scoped slot --> 
  12.       <template v-slot="{ item }"> 
  13.         <slot v-bind:item="item" /> 
  14.       </template> 
  15.     </v-for> 
  16.   </div> 
  17. </template> 

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

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

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

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

总结

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

本文主要内容:

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

 

责任编辑:赵宁宁 来源: 今日头条
相关推荐

2021-04-14 07:52:00

Vue 作用域插槽

2021-05-08 07:37:32

Vue 命名插槽

2019-10-15 09:05:07

域插槽组件前端

2020-08-10 08:30:35

Vue 数据插槽

2021-12-29 07:51:21

Vue3 插件Vue应用

2021-09-03 08:23:21

Vue 插槽子组件

2022-07-15 08:45:07

slotVue3

2021-11-26 10:08:57

鸿蒙HarmonyOS应用

2023-11-06 07:37:01

函数式插槽React

2020-03-24 08:32:24

vue作用域前端

2022-09-21 11:45:22

Vue组件插槽函数

2022-09-22 08:45:10

Vue组件函数

2023-09-05 08:23:56

SpringScope方法

2021-09-27 09:04:40

Vue.js代码库开发人员

2022-11-29 17:38:57

DockerfileARG作用域

2012-02-16 10:51:39

AMDOpteron皓龙处理服务器

2013-01-06 10:18:40

英特尔Haswell插槽

2010-06-04 15:30:44

Linux 查看内存

2011-03-18 09:27:00

Spring

2021-07-05 08:43:46

Spring Beanscope作用域
点赞
收藏

51CTO技术栈公众号