来自祖父母的组件,来自父母的数据,在孩子中呈现

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】:

将内容传递到普通插槽中定义了单个内容。在接收组件中,您只能使用&lt;slot&gt; 显示一次。内容在传入之前就已经创建好了,所以接收组件除了在某处显示它之外,对插槽的内容没有什么可做的。

在您的情况下,您需要在一个循环中多次重复插槽的内容。此外,您需要每个循环项目的渲染略有不同。

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>

所以KeywordListdetails 插槽现在是一个作用域插槽并将keywordId 传递给该插槽。但是,KeywordLI 组件的类似名称 details 插槽仍然只是一个普通插槽,因为它似乎不需要传递任何东西。

【讨论】:

谢谢!这非常有帮助。结合亚当的回答,我可以使用我需要的所有部分。我确信这需要一段时间才能理解和输入,所以我很感激。

以上是关于来自祖父母的组件,来自父母的数据,在孩子中呈现的主要内容,如果未能解决你的问题,请参考以下文章

ReactJS:在孩子和父母之间传递数据[重复]

如何在 VueJS 中将模板(插槽)从祖父组件传递给孙子?

父子组件按啥顺序呈现?

React-Native '不能将没有 YogaNode 的孩子添加到没有测量功能的父母!

Vue.js“超出最大调用堆栈大小”错误。将数据从父母传递给孩子失败

反应我必须重新渲染父母才能重新渲染孩子吗?