vue 在 Package 组件中传递槽

sr4lhrrt  于 2022-10-28  发布在  其他
关注(0)|答案(2)|浏览(169)

版本

2.6.11

复制链接

https://codesandbox.io/s/romantic-mahavira-1s4v6的最大值

重现步骤

参见“Wrapper”下面的内容

需要什么?

所有三种变体(不建议使用的语法和新语法,无论顺序如何)都应产生相同的结果

到底发生了什么?

在这个例子中,最后的“新语法”变体看起来不错,但是它不适用于Vuetify(不确定这是他们的问题还是Vue的问题)
根据您通常在网络上找到的内容,将插槽传递给子组件是使用以下语法完成的:

<slot v-for="(_, name) in $slots" :name="name" :slot="name" />
<template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData"><slot :name="name" v-bind="slotData" /></template>

不幸的是,这使用了标记为已弃用的slot和slot-scope属性。
作为当前替换,以下语法似乎是正确的:

<template v-for="(_, name) in $scopedSlots" v-slot:[name]="slotData">
  <slot :name="name" v-bind="slotData"/>
</template>
<template v-for="(_, name) in $slots" v-slot:[name]>
  <slot :name="name"/>
</template>

不幸的是,这并没有给予与旧语法相同的结果。根据传递作用域和非作用域插槽的顺序,要么作用域插槽根本不传递,要么非作用域插槽只在$scopedSlots中传递,Vuetify(可能还有其他库?)会忽略那些不应该被作用域的插槽。

iaqfqrcu

iaqfqrcu1#

通过将第二个迭代元素重命名为name之外的其他名称,我已经在三个变体之间实现了行为一致性。由于某种原因(可能是一个错误),第二次迭代中的v-slot:[name](即v-for)意外覆盖了前一次迭代,并导致此不一致。
通过重命名迭代变量,您很可能能够“调整”手头的问题:

<template v-for="(_, name) in $scopedSlots" v-slot:[name]="slotData">
  <slot :name="name" v-bind="slotData"/>
</template>
<template v-for="(_, someOtherName) in $slots" v-slot:[someOtherName]>
  <slot :name="someOtherName"/>
</template>

我会更深入地挖掘,以找到潜在的问题,但希望这个调整可以帮助您同时。
更新:
以下事实共同导致OP描述的不一致性:
1.任何由新语法v-slot表示的槽内容都被视为AST中的作用域槽(可能是为了性能优化)。
vue/src/compiler/parser/index.js
ef56410中的第665行
| | el.slotScope=slotBinding.value|| emptySlotScopeToken//将其强制到作用域插槽中以执行|
1.作用域插槽在其父AST节点(本例中为test-component节点)收集,并按其名称(即v-slot语法中冒号后的部分)进行索引。动态名称(括号中的名称)在作为Map索引时不作特殊处理。
vue/src/compiler/parser/index.js
ef56410中的第663行
| | el.插槽目标=名称|
vue/src/compiler/parser/index.js
ef56410中的第142至147行
| | 如果(元素.slotScope){|
| | //作用域插槽|
| | //将其保留在子列表中,以便v-else(-if)条件可以|
| | //找到它作为prev节点。|
| | 常量名称=元素.插槽目标||'“默认值”'|
| | ;(当前父项.作用域插槽||(当前父项.作用域插槽={}))[名称]=元素|
1.对于不赞成使用的旧语法<slot :slot="name">,此slot节点被视为AST上test-component节点的子节点,因此与test-component收集的作用域插槽分离。
事实1和2导致一个test-component中的第二次迭代覆盖第一次迭代对test-component节点的scopedSlot属性的贡献,只要第二次迭代对迭代元素使用与第一次迭代相同的标识符。
事实3通过将<slot :slot="name">视为子节点来防止这种冲突。
我想在这里ping@yyx990803,征求一下对此的意见。它应该被认为是“按预期工作”还是一个bug?

i7uq4tfw

i7uq4tfw2#

我想我在2.6.12中遇到了一个类似的问题。在模板中使用v-slot:[scopedSlot]="slotData"语法,没有任何slot属性的slot不能被传递。
<template v-for="(_, scopedSlot) of $scopedSlots" v-slot:[scopedSlot]="slotProps"><slot :name="scopedSlot" v-bind="slotProps"></slot></template>
当父节点规定:
<test-component><template #label>my label</template></test-component>
但是当父节点规定:
<test-component><template #item={item}>My item: {{item}}</template></test-component>
然而,如果测试组件没有分配slotProps,则第一个约定(#label)将通过,如下所示:
<template v-for="(_, scopedSlot) of $scopedSlots" v-slot:[scopedSlot]><slot :name="scopedSlot"></slot></template>
我试过v-slot:[scopedSlot]="{p = {}}"v-slot:[scopedSlot]="p"v-slot:[scopedSlot]="p={}"v-slot:[scopedSlot]="{...p}",但是这些组合都不起作用(而且原始的p={}无法编译,即使它是一个值函数参数表达式)。
现在,我使用@Nandiin的变通方法,将不同的名称与$scopedSlots和$slots一起使用,尽管我们真的不应该再使用$slots,至少在2.6.x中不应该这样

相关问题