如何使用Vue中的嵌套插槽(包括作用域插槽)
本文轉(zhuǎn)載自微信公眾號(hào)「大遷世界」,轉(zhuǎn)載本文請(qǐng)聯(lián)系大遷世界公眾號(hào)。
最近我弄清楚了如何遞歸地實(shí)現(xiàn)嵌套插槽,包括如何使用作用域插槽來(lái)實(shí)現(xiàn)。起因是我想看看是否可以構(gòu)建一個(gè)復(fù)制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>
第一個(gè)將正常打印列表,而第二個(gè)將每個(gè)項(xiàng)包裝在標(biāo)記中。
這不是一個(gè)非常有用的組件,但可以從中學(xué)到的最多,我們來(lái)看看。
無(wú)循環(huán)實(shí)現(xiàn)循環(huán)
通常,當(dāng)我們要渲染元素或組件的列表時(shí),可以使用v-for指令,但這次我們希望完全擺脫它。
那么,我們?nèi)绾卧诓皇褂醚h(huán)的情況下渲染項(xiàng)目列表呢?就是使用 「遞歸」。
我們可以使用遞歸來(lái)渲染項(xiàng)目列表。過(guò)程并不會(huì)復(fù)雜,我們來(lái)看看怎么做。
遞歸表示一個(gè)列表
我在大學(xué)里最喜歡的課程之一是[“編程語(yǔ)言概念”][1]。
對(duì)我來(lái)說(shuō),最有趣的部分是探索函數(shù)式編程和邏輯編程,并了解與命令式編程的區(qū)別(Javascript 和最流行的語(yǔ)言是命令式編程)。
這門(mén)課讓我真正了解如何使用遞歸,因?yàn)樵诩兒瘮?shù)語(yǔ)言中,一切都是遞歸。不管怎樣,從那門(mén)課我學(xué)到了可以使用遞歸地表示一個(gè)列表。
與使用數(shù)組不同,每個(gè)列表是一個(gè)值(頭)和另一個(gè)列表(尾)。
- [head, tail]
例如要表示列表[1、2、3],則可以遞歸方式表示為:
- [1, [2, [3, null]]]
我們必須以某種方式結(jié)束列表,因此我們使用null而不是另一個(gè)數(shù)組(也可以使用空數(shù)組)。
看到這里,你或許就可以明白了,我們可以使用此概念并將其應(yīng)用于我們的組件。相反,我們將遞歸嵌套組件以表示列表。
我們最終將渲染出這樣的內(nèi)容。注意我們“list”的嵌套結(jié)構(gòu):
- <div>
- 1
- <div>
- 2
- <div>
- 3
- </div>
- </div>
- </div>
誠(chéng)然,這與v-for渲染的效果并不完全相同,但這也不是本練習(xí)的重點(diǎn)。
構(gòu)建組件
首先,我們將解決遞歸渲染項(xiàng)目列表的問(wèn)題。
(1) 使用遞歸來(lái)渲染列表
這次我們使用一個(gè)普通數(shù)組,而不是使用前面介紹的遞歸列表:
- [1, 2, 3]
這里要討論兩種情況:
- 基本情形-渲染列表中的第一項(xiàng)
- 遞歸情形-渲染項(xiàng)目,然后沉浸下一個(gè)列表
我們把[1,2,3]傳給v-for
- <template>
- <v-for :list="[1, 2, 3]" />
- </template>
我們希望獲取列表中的第一項(xiàng),即1,并顯示它
- <template>
- <div>
- {{ list[0] }}
- </div>
- </template>
現(xiàn)在,該組件將渲染1,就像我們期望的那樣。
但是我們不能只渲染第一個(gè)值并停止。我們需要渲染值,然后還渲染列表的其余部分:
- <template>
- <div>
- {{ list[0] }}
- <v-for :list="list.slice(1)" />
- </div>
- </template>
我們不傳遞整個(gè)list數(shù)組,而是刪除第一項(xiàng)并傳遞新數(shù)組。第一個(gè)項(xiàng)目我們已經(jīng)打印出來(lái)了,所以沒(méi)有必要保留它。
順序是這樣的:
- 我們將[1,2,3]傳遞到v-for中進(jìn)行渲染
- 我們的v-for組件渲染1,然后將[2,3]傳遞到下一個(gè)v-for進(jìn)行渲染
- 取[2,3]并渲染2,然后將[3]傳遞到下一個(gè)v-for
- 最后一個(gè)v-for組件渲染出3,我們已經(jīng)打印出列表!
現(xiàn)在,我們的Vue應(yīng)用程序的結(jié)構(gòu)如下所示:
- <App>
- <v-for>
- <v-for>
- <v-for />
- </v-for>
- </v-for>
- </App>
可以看到,我們有幾個(gè)v-for組件,它們彼此嵌套在一起。最后一件事,我們需要停止遞歸
- <template>
- <div>
- {{ list[0] }}
- <v-for
- v-if="list.length > 1"
- :list="list.slice(1)"
- />
- </div>
- </template>
最終,渲染完所有項(xiàng)后,我們需要停止遞歸操作。
(2) 遞歸嵌套的插槽
現(xiàn)在,組件可以正常工作,但是我們也希望它與作用域內(nèi)插槽一起使用,因?yàn)檫@樣可以自定義渲染每個(gè)項(xiàng)的方式:
- <template>
- <v-for :list="list">
- <template v-slot="{ item }">
- <strong>{{ item }}</strong>
- </template>
- </v-for>
- </template>
(3) 嵌套插槽
一旦弄清楚了如何遞歸地嵌套插槽,就會(huì)對(duì)它癡迷一樣的感嘆:
- 嵌套n級(jí)的插槽
- 遞歸插槽
- 包裝組件將一個(gè)插槽轉(zhuǎn)換為多個(gè)插槽
首先,我們將簡(jiǎn)要介紹嵌套插槽的工作方式,然后介紹如何將它們合并到v-for組件中。
假設(shè)我們有三個(gè)組件:Parent、Child和Grandchild。我們希望傳遞來(lái)自Parent組件的一些內(nèi)容,并在Grandchild組件中渲染它。
從Parent開(kāi)始,我們傳遞一些內(nèi)容:
- // Parent.vue
- <template>
- <Child>
- <span>Never gonna give you up</span>
- </Child>
- </template>
我們?cè)贑hild組件中做一些事情,將在稍后介紹。然后我們的Grandchild組件獲取插槽并渲染內(nèi)容:
- // Grandchild.vue
- <template>
- <div>
- <slot />
- </div>
- </template>
那么,這個(gè)Child組件是什么樣的?
我們需要它從Parent組件獲取內(nèi)容并將其提供給Grandchild組件,因此我們將兩個(gè)不同的插槽連接在一起。
- // Child.vue
- <template>
- <Grandchild>
- <slot />
- </Grandchild>
- </template>
請(qǐng)記住,元素渲染出作為插槽傳遞到組件的內(nèi)容。因此,我們將從“Parent”中獲取該內(nèi)容,然后將其渲染到“Grandchild”插槽中。
(4) 添加作用域插槽
與嵌套作用域插槽唯一不同的是,我們還必須傳遞作用域數(shù)據(jù)。將其添加到v-for中,我們現(xiàn)在得到以下信息:
- <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>
首先讓我們看一下基本情況。
如果沒(méi)有提供插槽,則默認(rèn)元素內(nèi)部的內(nèi)容,并像以前一樣渲染list[0]。但是如果我們提供了一個(gè)slot,它會(huì)將其渲染出來(lái),并通過(guò)slot作用域?qū)⒘斜眄?xiàng)傳遞給父組件。
這里的遞歸情況類(lèi)似。如果我們將插槽傳遞給v-for,它將在下一個(gè)v-for的插槽中進(jìn)行渲染,因此我們得到了嵌套。它還從作用域槽中獲取item并將其傳遞回鏈。
現(xiàn)在,我們這個(gè)組件僅使用template就能實(shí)現(xiàn) v-for效果。
總結(jié)
我們做了很多事情,終于了解了如何創(chuàng)建一個(gè)僅使用 template 就能實(shí)現(xiàn)v-for的效果。
本文主要內(nèi)容:
- 遞歸地表示列表
- 遞歸組件
- 嵌套槽和嵌套作用域槽