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

时间:2019-02-01 10:12:30

标签: javascript vue.js

根据关于插槽范围的注释更新了代码

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

在我当前的项目中,我有一个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的slot-scope标记上定义<template>,但这似乎不起作用。

我想念什么吗?我不明白为什么App.vue需要知道或关心DataSlicer传递给其子级的内容。我将组件拆分得越多,问题就越复杂(例如,如果我将DataSlicer粘贴在另一个组件中以抽象api调用,这些调用目前在App.vue级别处理,那么App.vue还必须告诉组件将数据传递到其DataSlicer子级[ren]。

也许我只是在这里停留在React的思考上,还有另一种或更好的方法可以做到这一点?

编辑:

如果有帮助,我可以使用这样的渲染功能完成我想要的:

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

这感觉有点hacking /脆弱,并且就像我在可能有更好的方法的时候,以一种“反应方式”扩展Vue一样。

编辑2:

经过更多的研究和实验,我还尝试了提供/注入方法。这项工作有效(通过使用defineObjectProperty为传递的属性绑定动态获取器),但是这意味着必须显式编写子组件以接受提供的道具,而不仅仅是接受该道具,无论它是由父组件还是直接提供。

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

这是React中很常见的模式,实现起来很简单,所以我仍然很好奇是否还有另一种实现方法与Vue的工作方式更一致。

我正在尝试构建可重用,自包含且可组合的组件,因此每次将它们一起使用时,必须在父组件的<template>标签中指定slot-scope并不能真正使就我的目的而言。我的孩子组成部分不应该关心他们的道具来自哪里,我的父母组成部分也不应该关心他们的孩子正在向自己的孩子传递什么道具。

1 个答案:

答案 0 :(得分:1)

我终于可以使用Vue 2.6中的新v-slot范围来完成我想要的工作,该描述如下:https://github.com/vuejs/vue/issues/9306

我遇到的问题之一是,Vue团队将我正在寻求的“国家提供者”方法视为反模式,因为不清楚道具的来源。我明白了他们的观点,并且我认为新语法在清晰和避免<template>标签包裹子组件的过多重复之间提供了良好的平衡。它还简化并明确了组件无需接受它们来自何处(我的提供/注入问题)的能力,即可同时使用提供的道具和“常规”道具。

最终结果看起来像这样:

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的其他人有帮助。如果有人提出更好的答案,我将保留这个问题。