通过 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 中的 <template>
标签上定义 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 (<component>
),但它最终变得非常混乱,因为我本质上是将 $slots.default 中收到的已定义组件重新初始化为动态组件 - - 当我希望这些组件也有子组件时,它还会引入一些递归怪异,并且很难处理非组件子组件。
这是 React 中很常见的模式,实现起来也很简单,所以我仍然很好奇是否有另一种更符合 Vue 做事方式的方式来实现。
我正在尝试构建可重用、自包含和可组合的组件,因此每次一起使用时必须在父组件的 <template>
标记中指定 slot-scope 并没有真正意义我的目的。我的子组件不应该关心他们的 props 来自哪里,我的父组件不应该关心他们的孩子传递给他们自己的孩子的 props。
【问题讨论】:
在 DataSlicer.vueslot-scope
只是命名空间。我更新了我的代码以使其更清晰(这不会影响父组件为什么要处理这个问题的根本问题)。
【参考方案1】:
我终于能够使用 Vue 2.6 中的新 v-slot
范围做我想做的事,如下所述:https://github.com/vuejs/vue/issues/9306
我的部分问题是 Vue 团队将我所采用的“状态提供者”方法视为一种反模式,因为不清楚 props 的来源。我明白他们的观点,并且我认为新语法在清晰和避免包裹子组件的 <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>
DataGetter
和 DataSlicer
渲染函数:
render(h)
if (this.$scopedSlots.default)
return h(
'div',
this.$scopedSlots.default( data: this.data )
)
我希望这对来自 React 的其他人有所帮助。我会留下这个问题,以防其他人提出更好的答案。
【讨论】:
以上是关于通过 Vue.js 中的 slot-scope 将 props 传递给所有子项的正确方法的主要内容,如果未能解决你的问题,请参考以下文章