You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue中通过函数式包装器传递插槽时如何保留子组件原有插槽?

问题描述

现有如下代码:

父组件代码

<script setup>
import { ref } from 'vue'
import Input from './Input.js'
import Text from './Text.vue'

const msg = ref('Hello World!')
</script>

<template>
  <Input label="Message">
    <Text v-model="msg">
      <template #icon>❤️</template>
    </Text>
  </Input>
</template>

Input.js

import {h} from 'vue';
export default function Input({label}, {slots}){
  return slots.default().map(vnode => h(vnode, {}, {label: () => label}))
};

Text.vue

<script setup>
const model = defineModel();
</script>

<template>
  <div :class="{iconed: $slots.icon}">
    <div v-if="$slots.label"><slot name="label"/></div>
    <span v-if="$slots.icon" class="icon"><slot name="icon"/></span>
    <input v-model="model"/>
  </div>
</template>

需求是保留Text组件的icon插槽,且希望保持现有模板写法,明确该插槽属于Text组件(已知可将插槽移至Input组件再转发,但不希望这么做)。

解决方案

问题根源在于Input组件创建新vnode时,直接用{label: () => label}替换了原vnode的插槽集合,导致Text组件的icon插槽丢失。只需合并原插槽与新增的label插槽即可解决:

修改Input.js代码如下:

import {h} from 'vue';
export default function Input({label}, {slots}){
  return slots.default().map(vnode => {
    // 合并原vnode的所有插槽与新增的label插槽
    const mergedSlots = {
      ...vnode.children,
      label: () => label
    }
    return h(vnode, {}, mergedSlots)
  })
};

此修改既保留了Text组件的icon插槽,又能正常传递Input的label插槽,完全无需改动原模板结构,仍可明确icon插槽属于Text组件。


内容的提问来源于stack exchange,提问作者Alexander Nenashev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 01:04:55