版本
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(可能还有其他库?)会忽略那些不应该被作用域的插槽。
2条答案
按热度按时间iaqfqrcu1#
通过将第二个迭代元素重命名为
name
之外的其他名称,我已经在三个变体之间实现了行为一致性。由于某种原因(可能是一个错误),第二次迭代中的v-slot:[name]
(即v-for
)意外覆盖了前一次迭代,并导致此不一致。通过重命名迭代变量,您很可能能够“调整”手头的问题:
我会更深入地挖掘,以找到潜在的问题,但希望这个调整可以帮助您同时。
更新:
以下事实共同导致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?
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中不应该这样