Vue:忽略已定义插槽的插槽包装器
Posted
技术标签:
【中文标题】Vue:忽略已定义插槽的插槽包装器【英文标题】:Vue: wrapper for slots ignoring already-defined slots 【发布时间】:2021-01-20 14:07:01 【问题描述】:Vue 对象有一个非常有用的成员,叫做$attrs
。 $attrs 所做的是包含所有未被识别为当前组件道具的属性。 $attrs
的一个很好的例子是 here。
我想知道$attrs
是否有对应于$scopedSlots
的等价物。我目前正在使用类似于 https://***.com/a/50892881/6100005 的第一个建议的方法。 $scopedSlots
的问题是它也通过了已经定义的槽。要在此处使用该示例:
<template>
<wrapper>
<b-table :foo="foo" v-bind="$attrs" v-on="$listeners">
<template v-for="(_, slot) of $scopedSlots" v-slot:[slot]="scope"><slot :name="slot" v-bind="scope"/></template>
</b-table>
<slot name="mySlot"></slot>
</wrapper>
</template>
<script>
export default
props:
// let's pretend that `b-table` has a prop `foo` that is default `false`
foo:
type: boolean,
default: true,
</script>
现在,由于$attrs
的行为,foo
不会被绑定两次,但mySlot
将被发送到wrapper
和b-table
。
那么,我怎么能把所有的插槽都传下来除了我定义自己的插槽?
我的一个想法是拥有
computed:
bTableSlots()
Object.keys(this.$scopedSlots)
.filter( key => key!=='mySlot' )
.reduce( (res, key) => (res[key] = this.$scopedSlots[key], res), );
然后
<template v-for="(_, slot) of bTableSlots" v-slot:[slot]="scope"><slot :name="slot" v-bind="scope"/></template>
想知道是否有更好的方法来做到这一点。谢谢!
【问题讨论】:
【参考方案1】:那么除了我自己定义的那个,怎么能把所有的槽都传下去呢?
为什么这甚至是一个问题?如果<b-table>
没有名称为mySlot
的命名槽,它将忽略它——最后它只是它的$scopedSlots
属性中的一个条目,组件永远不会访问。而且因为作用域插槽是作为函数传递的,所以您无需支付任何额外价格。
当 Vue 编译器看到 slot 的内容 (<template #slotName>
) 时,它会获取该内容并将其编译成 VNode
s 的 Array
或 VNode
s 的返回 Array
的函数并传递下去到子组件。您的子组件进一步传递它的事实不会产生任何额外的成本。它是对现有数组的引用或对现有函数的引用(对于作用域插槽),在这两种情况下,如果组件进一步向下不知道插槽具有完全相同的名称,则不存在额外费用,除了$scopedSlots
中多了一个条目...
如果您觉得这是一个问题,恐怕过滤是唯一的方法 - 您可以按照自己的方式或通过一些辅助数组 [ 'slot1', 'slot2' ]
定义所有现有的 b-table
插槽并过滤其他所有内容(恕我直言,不是更好)每次b-table
添加新插槽时都需要更新组件)......
我理解这个想法并看到与 $attrs
的相似之处 - 组件上可能有 $unknownSlots
之类的东西来保存当前组件未定义的插槽,但现在 Vue 公共 API 中没有这样的东西。 .
【讨论】:
我更担心性能而不是命名冲突。你是说因为$scopedSlots
是一个以name
s 为键的对象,如果我向其中添加一个未使用的条目,它对性能的影响会最小吗?如果是这样,这是一个可以接受的解决方案
如果添加“未使用”插槽,代价将是编译时间(构建时)和 JS 引擎解析传递的插槽的渲染函数所需的内存 + 时间。但是如果你传递“mySlot”,创建的函数将被你的组件使用(没有浪费)。该函数也传递到'b-table'$scopedSlots
这一事实是无关紧要的......它是相同的函数
@MaxCoplan 扩展了我的答案,重点关注性能。希望现在很清楚......以上是关于Vue:忽略已定义插槽的插槽包装器的主要内容,如果未能解决你的问题,请参考以下文章