跨多组件传递作用域插槽异常:动态数据失效与重复插槽报错
Hey there, let’s tackle this "Duplicate presence of slot 'default'" error you’re facing. I’ve run into similar headaches when working with nested slot-based components, so let’s break down what’s going on and how to fix it.
What’s Causing the Error?
This error pops up when Vue detects the same default slot being registered multiple times during rendering. In your case, static content works because it’s a simple, single slot pass-through, but dynamic data (especially with loops) triggers a conflict—likely because your SearchAndList component is accidentally repeating the default slot somewhere in its template.
Step-by-Step Fixes
1. Audit Your SearchAndList Component’s Slot Logic
First, check if you’re using <slot /> more than once in SearchAndList.vue. A common mistake is passing the default slot both to the wrapper and the inner list.vue component, like this:
<!-- ❌ Bad: Duplicate default slot usage --> <template> <div class="search-container"> <SearchBar /> <slot /> <!-- First default slot --> <ListComponent> <slot /> <!-- Second duplicate default slot --> </ListComponent> </div> </template>
This creates a conflict because Vue can’t resolve two separate default slots being rendered at once.
2. Use Named Slots to Avoid Conflicts
The cleanest fix is to use a named slot for the list items, so SearchAndList explicitly passes only the necessary content to list.vue. Here’s how to adjust your components:
SearchAndList.vue:
<template> <div class="search-and-list"> <SearchBar @search="handleSearch" /> <!-- Pass a named slot to the inner List component --> <ListComponent :data="listData"> <template #list-item="{ item }"> <slot name="list-item" :item="item" /> </template> </ListComponent> </div> </template> <script setup> import ListComponent from './list.vue'; import SearchBar from './SearchBar.vue'; const props = defineProps({ listData: { type: Array, required: true } }); const handleSearch = (keyword) => { // Add your search filtering logic here }; </script>
list.vue:
<template> <div class="list"> <div v-for="item in data" :key="item.id"> <!-- Use the named slot for each list item --> <slot name="list-item" :item="item" /> </div> </div> </template> <script setup> defineProps({ data: { type: Array, required: true } }); </script>
page.vue:
<template> <SearchAndList :listData="dynamicItems"> <!-- Define the named slot content for dynamic items --> <template #list-item="{ item }"> <div>{{ item.title }} - {{ item.description }}</div> </template> </SearchAndList> </template> <script setup> import SearchAndList from './SearchAndList.vue'; import { ref } from 'vue'; const dynamicItems = ref([ { id: 1, title: 'First Item', description: 'Dynamic content 1' }, { id: 2, title: 'Second Item', description: 'Dynamic content 2' }, { id: 3, title: 'Third Item', description: 'Dynamic content 3' } ]); </script>
3. Alternative: Pass Render Logic via Props
If you prefer not to use slots, you can pass a render function as a prop from page.vue to SearchAndList, which then forwards it to list.vue:
SearchAndList.vue:
<template> <div class="search-container"> <SearchBar /> <ListComponent :data="listData" :renderItem="renderItem" /> </div> </template> <script setup> import ListComponent from './list.vue'; defineProps(['listData', 'renderItem']); </script>
list.vue:
<template> <div class="list"> <div v-for="item in data" :key="item.id"> <component :is="renderItem(item)" /> </div> </div> </template> <script setup> defineProps(['data', 'renderItem']); </script>
page.vue:
<template> <SearchAndList :listData="dynamicItems" :renderItem="renderItem" /> </template> <script setup> import { h } from 'vue'; const renderItem = (item) => { return h('div', `${item.title}: ${item.description}`); }; </script>
Quick Additional Checks
- Make sure you’re not using
<slot />inside av-forloop in any component—this will create a slot instance for every iteration, triggering the duplication error. - If you’re on an older Vue version, try upgrading to Vue 3.3+; some slot handling bugs were fixed in recent releases.
内容的提问来源于stack exchange,提问作者MWit

