通过 Vue.js 中的 slot-scope 将 props 传递给所有子项的正确方法

Posted

技术标签:

【中文标题】通过 Vue.js 中的 slot-scope 将 props 传递给所有子项的正确方法【英文标题】:Correct way to pass props to all children through slot-scope in Vue.js 【发布时间】:2019-06-25 21:34:04 【问题描述】:

根据 cmets 更新了有关 slot-scope 的代码

来自 React,我很难理解 Vue 如何使用 slot 和 slot-scope 将 props 传递给子组件。

在我当前的项目中,我有一个 DataSlicer 组件,它接收 data 道具并对其执行一些操作。然后我想通过<slot> 将操作数据传递给子组件。我知道slot-scope 是这样做的方法,但它似乎只有在 parent 组件告诉孩子将某些东西传递给自己的孩子时才有效——这似乎违背了整个观点(在组合和关注点分离的术语)。

这就是我现在的工作,基于阅读How to pass props using slots from parent to child -vuejs

App.vue

<DataSlicer
    v-if="data"
    y-axis-dimension="Subparameter"
    x-axis-dimension="Year"
    value-dimension="Total_Registrations"
    :filters=""
    :data="data"
>
    <template slot-scope="childProps">
        <Chart :title="title" :series-data="childProps.slicedData" />
    </template>
</DataSlicer>

DataSlicer.vue

<template>
  <div>
    <slot :slicedData="slicedData"/>
  </div>
</template>

我的期望是我可以在 DataSlicer.vue 中的 &lt;template&gt; 标签上定义 slot-scope,但这似乎不起作用。

我错过了什么吗?我不明白为什么 App.vue 需要知道或关心 DataSlicer 传递给它的孩子的东西。当我拆分组件越多,问题就越复杂(例如,如果我将 DataSlicer 粘贴在另一个组件中以抽象当前在 App.vue 级别处理的 api 调用,那么 App.vue 还必须说明这一点组件将数据传递给它的 DataSlicer child[ren])。

也许我只是在这里停留在 React 思维中,并且有另一种或更好的方法来做到这一点?

编辑:

如果有帮助,我可以使用如下渲染函数完成我想要的:

render: function (createElement) 
    return createElement(
      'div',
      this.$slots.default.map(vNode => 
        if (vNode.componentOptions) 
          vNode.componentOptions.propsData.slicedData = this.slicedData;
        
        return vNode;
      )
    )
  

这感觉相当 hackish/脆弱,而且当可能有更好的方法时,我正在扩展 Vue 以“反应方式”做某事。

编辑 2:

经过更多的研究和实验,我也尝试了提供/注入方法。这可行(通过使用 defineObjectProperty 为正在传递的属性绑定动态 getter),但这意味着必须显式编写子组件以接受提供的道具,而不是仅仅接受由父组件或直接提供的道具。

我也尝试过使用动态组件和 v-for (&lt;component&gt;),但它最终变得非常混乱,因为我本质上是将 $slots.default 中收到的已定义组件重新初始化为动态组件 - - 当我希望这些组件也有子组件时,它还会引入一些递归怪异,并且很难处理非组件子组件。

这是 React 中很常见的模式,实现起来也很简单,所以我仍然很好奇是否有另一种更符合 Vue 做事方式的方式来实现。

我正在尝试构建可重用、自包含和可组合的组件,因此每次一起使用时必须在父组件的 &lt;template&gt; 标记中指定 slot-scope 并没有真正意义我的目的。我的子组件不应该关心他们的 props 来自哪里,我的父组件不应该关心他们的孩子传递给他们自己的孩子的 props。

【问题讨论】:

在 DataSlicer.vue 中定义了 slot 范围内的属性 'slicedData'。在 App.vue 中, @AndrewCastellano 嗨,安德鲁,是的,这段代码有效——在某个地方,我想到了可以使用对象解构语法来传递我想要的东西,但现在我想我明白 slot-scope 只是命名空间。我更新了我的代码以使其更清晰(这不会影响父组件为什么要处理这个问题的根本问题)。 【参考方案1】:

我终于能够使用 Vue 2.6 中的新 v-slot 范围做我想做的事,如下所述:https://github.com/vuejs/vue/issues/9306

我的部分问题是 Vue 团队将我所采用的“状态提供者”方法视为一种反模式,因为不清楚 props 的来源。我明白他们的观点,并且我认为新语法在清晰和避免包裹子组件的 &lt;template&gt; 标记的过多样板之间提供了良好的平衡。它还简化并明确了组件获取提供的道具和“常规”道具而不关心它们来自哪里的能力(我的提供/注入问题)。

最终结果如下所示:

App.vue

<DataGetter ...other props v-slot=" data ">
      <DataSlicer ...other props :data="data" v-slot=" slicedData ">
        <!-- Using provided data prop -->
        <Chart :data="slicedData" />
        <!-- Data prop explicitly defined -->
        <Chart :data="[ 1, 2, 3 ]" />
      </DataSlicer>
</DataGetter>

DataGetterDataSlicer 渲染函数:

render(h) 
    if (this.$scopedSlots.default) 
      return h(
        'div',
        this.$scopedSlots.default( data: this.data )
      )
    
  

我希望这对来自 React 的其他人有所帮助。我会留下这个问题,以防其他人提出更好的答案。

【讨论】:

以上是关于通过 Vue.js 中的 slot-scope 将 props 传递给所有子项的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

Vue提升:理解vue中的 slot-scope=“scope“

深入理解vue中的slot与slot-scope

关于Element UI Table 的 slot-scope

关于Element UI Table 的 slot-scope

关于slot-scope="scope"

vue中的slot与slot-scope