来自祖父母的组件,来自父母的数据,在孩子中呈现
Posted
技术标签:
【中文标题】来自祖父母的组件,来自父母的数据,在孩子中呈现【英文标题】:Component from grandparent, data from parent, rendered in child 【发布时间】:2020-03-18 19:29:47 【问题描述】:我有一个祖父组件、一个父组件和一个子组件。问题:如果祖父将一个组件传递给子组件中的插槽,父组件可以插入数据吗?出现在孩子身上?
视觉上是这样的:
--------Grandparent -------------> Parent -------------> child------------>Slot
/|\ /|\ /|\
| | |
[Slot component identified ] | [Data added]| [data shows in slot component]
需要注意的是,父项是一个列表,子项是列表项。孩子们确实收到了插槽,但我无法让父母将个人 ID 传递给孩子们。
实际模板如下所示:祖父(列表容器):
<template>
...
<KeywordList v-model="activeKeywordIds">
<KeywordDetailsEditContent slot="details" v-if="activity === 'editResumeContent'"/>
<template v-slot:details>
<KeywordDetails_Editing v-if="editing"/>
<KeywordDetails_PrivView v-if="viewing && loggedIn"/>
<KeywordDetails_PublicView v-else />
</template>
</KeywordList>
...
</template>
父(关键字列表):
<template>
...
<KeywordLI
v-for="keywordId of value"
:key="keywordId"
:str-keyword-id="keywordId"
>
<template v-slot:details>
<slot name="details"></slot>
</template>
</KeywordLI>
...
</template>
儿童(关键字LI):
<template>
...
<div
class="detailsContainer"
ref="detailsContainer"
v-if="appWidthDescription > 1"
>
<div ref="details" style="height: fit-content">
<slot name="details"></slot>
</div>
</div>
..
</template>
插槽组件
<template>
strKeywordId [Other computed/fetched details depending on which component was sent]
</template>
所以祖父母知道渲染什么细节,但是直到父组件才分解出细节,而子组件是它们需要聚集在一起的地方。
到目前为止,这还没有奏效:
-
在父组件的插槽中添加一个道具。
<template>
...
<KeywordList>
...
<KeywordLI
v-for="keywordId of value"
:key="keywordId"
:str-keyword-id="keywordId"
>
<template v-slot:details>
<slot name="details" :str-keyword-id='keywordId'></slot> //<----Adding prop to slot
</template>
</KeywordLI>
...
</KeywordList>
...
</template>
-
将 prop 添加到父模板中
<template>
...
<KeywordLI
v-for="keywordId of value"
:key="keywordId"
:str-keyword-id="keywordId"
>
<template v-slot:details :str-keyword-id='keywordId'> //<----Adding prop directly to slot
<slot name="details"></slot>
</template>
</KeywordLI>
...
</template>
【问题讨论】:
我很难按照这里的命名。子组件是KeywordLI
吗?父组件是KeywordList
?祖父母模板和父模板似乎都包含KeywordList
,我正在努力协调。我也无法弄清楚哪个组件“插槽组件”是。这是名称以KeywordDetails
开头的组件之一吗?
感谢您查看@skirtle-我输入的代码不正确。当前版本是正确的。回答您的问题:子组件是“KeywordLI”,父组件是“KeywordList”。 “插槽组件”是 KeywordDetails。因此,祖父母将知道哪些“KeywordDetails”是合适的,并将相应的组件发送到适当的 KeywordList 插槽,然后将其转发到适当的 KeywordLI 插槽。
【参考方案1】:
如果我没有做对,请纠正我,但在一个非常简单的例子中,你需要的是:
您在这里的工作示例 => codesandbox
注意:我没有使用您的组件,因为您不会学习。尝试使用我准备的内容并满足您的需求:-)
现在!
在您的 Child 组件中,您需要准备一个slot
:
<template>
<div>
<h3>Child</h3>
<slot name="details">default Child slot</slot> //default is optional
</div>
</template>
在 Paren 组件中,您需要将 Parent 自己的插槽放入 Child 插槽中。另外:绑定你想要的东西(一些data
),你的祖父母需要使用。
<template>
<div>
<h2>Parent</h2>
<Child>
<template v-slot:details>
<slot name="details" :id="3">default Parent slot</slot> // 3 is whatever you need to pass up
</template>
</Child>
</div>
</template>
然后在您的祖父母中,您使用父母通过scopedSlot
发送的内容并将其一直传递给孩子。
<template>
<div>
<h1>Grandparent</h1>
<Parent>
<template v-slot:details="props">
<slot
name="details"
>default Grandparent slot rendered in child komponent with id props.id send from parent</slot>
</template>
</Parent>
</div>
</template>
注意,发送所有信息的是您的祖父组件,但给他一些信息的是您的父组件。
希望有帮助 ;-)
【讨论】:
这很有帮助!你提供的那个codeandbox特别有用,所以感谢你花时间把它放在一起。我对细节仍然有些模糊,但是在您的回答、@skirtle 的回答以及我可以使用的我自己的工作版本之间,我想我将能够获得所需的清晰度。再次非常感谢!【参考方案2】:将内容传递到普通插槽中定义了单个内容。在接收组件中,您只能使用<slot>
显示一次。内容在传入之前就已经创建好了,所以接收组件除了在某处显示它之外,对插槽的内容没有什么可做的。
在您的情况下,您需要在一个循环中多次重复插槽的内容。此外,您需要每个循环项目的渲染略有不同。
Vue 有一些东西可以处理这个场景:作用域插槽。
官方文档:https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots
有多种方法可以考虑作用域插槽。您可能希望将它们视为可以传递给后代组件的迷你模板。将它们视为回调函数的另一种方式,允许后代将数据传回链上。
作用域槽有很多可能的用途,但模板列表是最常见的例子之一。
让我们从你的祖父组件开始:
<template>
<KeywordList v-model="activeKeywordIds">
<template v-slot:details=" keywordId ">
<KeywordDetailsEditContent
v-if="activity === 'editResumeContent'"
:str-keyword-id="keywordId"
/>
<KeywordDetails_Editing
v-if="editing"
:str-keyword-id="keywordId"
/>
<KeywordDetails_PrivView
v-if="viewing && loggedIn"
:str-keyword-id="keywordId"
/>
<KeywordDetails_PublicView
v-else
:str-keyword-id="keywordId"
/>
</template>
</KeywordList>
</template>
对此有几点说明:
-
通过添加
=" keywordId "
部分,我们现在处于作用域插槽领域。
str-keyword-id
需要被定义为这 4 个组件的每个组件。
确实有点重复。您可能要考虑改用is
。 https://vuejs.org/v2/api/#is
您将 Vue 2.6 v-slot
语法与 Vue 2.5 slot="details"
语法混合在一起。我已将它们合并以仅使用前者。
当然,最大的问题是keywordId
来自哪里?
v-slot:details=" keywordId "
正在接收传递给作用域槽的数据。你可以认为它大致类似于如下所示的回调函数:
function details ( keywordId )
// ...
这里的 keywordId
部分只是函数第一个参数的对象解构。
现在我们需要“调用”这个作用域插槽并将正确的参数传递给它。通常看起来像这样:
<slot name="details" :keywordId="blah" />
除name
之外的所有属性都将封装在一个对象中,并作为唯一参数传递给作用域槽“函数”。
这变得更复杂了,因为这个问题有多个槽,所以我们需要小心我们传递到哪里。
所以在KeywordList
中我们会有:
<template v-slot:details>
<slot name="details" :keywordId="keywordId" />
</template>
所以KeywordList
的details
插槽现在是一个作用域插槽并将keywordId
传递给该插槽。但是,KeywordLI
组件的类似名称 details
插槽仍然只是一个普通插槽,因为它似乎不需要传递任何东西。
【讨论】:
谢谢!这非常有帮助。结合亚当的回答,我可以使用我需要的所有部分。我确信这需要一段时间才能理解和输入,所以我很感激。以上是关于来自祖父母的组件,来自父母的数据,在孩子中呈现的主要内容,如果未能解决你的问题,请参考以下文章
React-Native '不能将没有 YogaNode 的孩子添加到没有测量功能的父母!