组件作用域插槽分发,将作用域插槽从父组件传递到子组件(Select、FormSelect)
背景
二次封装 Select 组件: src\common\components\Select\index.vue
<template>
<el-select
ref="select"
v-selectdisabled="{ multiple, options, props: curProps, attrs: curAttrs }"
v-bind="curAttrs"
v-on="curListeners">
<!-- 默认的el-option不满足需求时,外部直接通过插槽覆盖 -->
<slot name="options" :options="options">
<el-option
v-for="(item, index) in options"
:key="customkey ? item[customkey] : index"
:label="typeof curProps.label === 'function' ? curProps.label(item) : item[curProps.label]"
:value="typeof curProps.value === 'function' ? curProps.value(item) : item[curProps.value]"
:disabled="!!item[curProps.disabled]"
@click.native="handleClickOption(item, index)">
<slot :item="item" :index="index"></slot>
</el-option>
</slot>
</el-select>
</template>
其中提供了 options 插槽(v-slot:options)和单项n个 option 的插槽(v-slot:default)。
再次进行封装 FormSelect 组件,这里我们需要拿到 Select 内的作用域插槽并往下传递给使用 FormSelect 的组件,最终效果如下:
<FormSelect
v-model="id"
:options="users">
<template v-slot:options="{ options }">
<el-option v-for="(item, key) in options" :key="key" :value="item.value" :label="`自定义的options ${item.label}`"></el-option>
</template>
</FormSelect>
<FormSelect
v-model="id"
:options="users">
<template v-slot:default="{ item }">自定义的option {{ item.label }}</template>
</FormSelect>
问题
如果通过 $slots
这种方式传递,可以传递非作用域插槽,但无法取到插槽的作用域。
<slot v-for="(_, name) in $slots" :name="name" :slot="name" />
解决方案
通过作用域插槽 vm.$scopedSlots
进行传递
<template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData"><slot :name="name" v-bind="slotData"/></template>
<!-- vue@2.6.0写法 -->
<template v-for="(_, name) in $scopedSlots" v-slot:[name]="slotData"><slot :name="name" v-bind="slotData"/></template>
参考
Vue: Pass Slots through from Parent to Child Components
Thanks!
Here is the example in new syntax with customization:
<!-- pass through scoped slots -->
<template v-for="(_, scopedSlotName) in $scopedSlots" v-slot:[scopedSlotName]="slotData">
<slot :name="scopedSlotName" v-bind="slotData" />
</template>
<!-- pass through normal slots -->
<template v-for="(_, slotName) in $slots" v-slot:[slotName]>
<slot :name="slotName" />
</template>
<!-- after iterating over slots and scopedSlots, you can customize them like this -->
<template v-slot:overrideExample>
<slot name="overrideExample" />
<span>This text content goes to overrideExample slot</span>
</template>