在uni-app组件的v-for里使用slot时多渲染了一个<slot></slot>导致微信开发工具报好多警告

在uni-app组件的v-for里使用slot时多渲染了一个<slot></slot>导致微信开发工具报好多警告

开发环境 版本号 项目创建方式
Windows window 10 CLI

示例代码:

<swiper-item class="flexColumn fBlock" v-for="item,index in dataList" :key="item?.id||index">  
    <slot :item="item" :index="index"></slot>  
</swiper-item>

操作步骤:

<swiper-item class="flexColumn fBlock" v-for="item,index in dataList" :key="item?.id||index">  
    <slot :item="item" :index="index"></slot>  
</swiper-item>

预期结果:

只编译出一个slot

实际结果:

看版本对比,新版编译的时候特意加了默认插槽的判断,所以 编译出了两个slot,一个是具名插槽,一个是默认插槽,导致默认插槽在开发者工具里报了好多警告。

bug描述:

在v-for里写入默认插槽,看下面代码

<swiper-item class="flexColumn fBlock" v-for="item,index in dataList" :key="item?.id||index">  
    <slot :item="item" :index="index"></slot>  
</swiper-item>

编译出来的结果多了个<slot></slot>导致微信开发工具报了一堆警告([Component] More than one slot named “default” are found inside a single component instance (in component “components/bSwiper/bSwiper”). The first one was accepted.),编译结果看下面代码

<swiper-item wx:for="{{a}}" wx:for-item="item" wx:key="d" class="flexColumn fBlock data-v-4d28a2b6">  
      <slot name="{{item.a}}"></slot>  
      <slot></slot>  
  </swiper-item>>

看了下编译的文件codegen.js。新版多了对默认插槽的判断。代码如下

if (node.tagType === compiler_core_1.ElementTypes.SLOT) {  
                const isEmptyDefaultSlot = node.props.some((p) => (p.type === compiler_core_1.NodeTypes.ATTRIBUTE &&  
                    p.name === 'name' &&  
                    p.value?.content === uni_shared_1.SLOT_DEFAULT_NAME) ||  
                    (p.name === 'bind' &&  
                        p.slotName ===  
                            uni_shared_1.SLOT_DEFAULT_NAME)) && node.children.length === 0;  
                // 当存在 <slot name="default" :xxx="xxx"> 时,在后面添加 <slot></slot>,使默认插槽生效  
                if (isEmptyDefaultSlot) {  
                    genSlot(node, context);  
                    return genSlot((0, shared_1.extend)({}, node, { props: [], children: [], loc: {} }), context);  
                }  
                return genSlot(node, context);  
            }

更多关于在uni-app组件的v-for里使用slot时多渲染了一个<slot></slot>导致微信开发工具报好多警告的实战教程也可以访问 https://www.itying.com/category-93-b0.html

10 回复

你的完整的代码是怎么写的?

更多关于在uni-app组件的v-for里使用slot时多渲染了一个<slot></slot>导致微信开发工具报好多警告的实战教程也可以访问 https://www.itying.com/category-93-b0.html


不是单独这一个组件这样的。其他所有组件都是这样的。

回复 z***@163.com: 发下可复现demo

<template> <swiper class="bSwiper" @change="change"> <swiper-item class="flexColumn fBlock" v-for="item,index in dataList" :key="item?.id||index"> <slot :item="item" :index="index"></slot> </swiper-item> </swiper> </template> <script setup lang="ts"> defineOptions({ name: "bSwiper", options: { virtualHost: true, multipleSlots: true, }, }) type DataItem = { image_url : string; [key:string]:any; }; const props = defineProps({ dataList: { type: Array as PropType<DataItem[]>, default: () => [] }, }) const emits = defineEmits(["change"]); //const current = ref<any>(0); const change = (e : AnyObject) => { emits("change", e.detail) } </script>

类似这样的简单封装一个Swiper组件。编译出来的就是两个slot。就是for里面有默认插槽的情况下都会出现编译出两个slot的情况。编译结果就是下面这样,多了一个<slot></slot> ,代码虽然可以使用,不过开发工具报好多警告的: <swiper-item wx:for="{{a}}" wx:for-item="item" wx:key="d" class="flexColumn fBlock data-v-4d28a2b6">
<slot name="{{item.a}}"></slot>
<slot></slot>
</swiper-item>> 我临时把编译文件改回以前的了。 if (isEmptyDefaultSlot) {
return genSlot(node, context); //临时解决bug,提前return了,不会编译出两个slot。
return genSlot((0, shared_1.extend)({}, node, { props: [], children: [], loc: {} }), context);
}

你外面怎么使用这个组件?isEmptyDefaultSlot 是为了解决默认插槽的显示问题,我看看怎么优化下这里

回复 DCloud_UNI_JBB: 优化了吗这里

回复 2***@qq.com: 等下一个alpha

类似这样: <bSwiper :dataList="swiperBanner">
<template v-slot="{item}">
<view class=“fBlock” @tap=“goto(item.links)”>
<bImg noBgColor class="sImg iSwiper" :lazyLoad="false" :defaultType="999" :borderRadius="10" :src="item.litpic">
</bImg>
</view>
</template>
</bSwiper>

临时解决方案可以参考这个帖子 https://ask.dcloud.net.cn/question/215135

这是一个已知的uni-app编译问题。在v-for循环中使用具名插槽时,编译器会额外生成一个默认插槽,导致微信开发者工具报出多个default slot的警告。

问题分析: 从你提供的编译代码可以看出,编译器在处理<slot :item="item" :index="index">时,将其编译为具名插槽<slot name="{{item.a}}"></slot>,但同时添加了一个空的默认插槽<slot></slot>,这违反了微信小程序的单slot限制。

临时解决方案:

  1. 使用template包装
<swiper-item class="flexColumn fBlock" v-for="item,index in dataList" :key="item?.id||index">
    <template>
        <slot :item="item" :index="index"></slot>
    </template>
</swiper-item>
  1. 避免在v-for中直接使用slot,改为在父组件中循环:
// 父组件
<b-swiper>
    <swiper-item v-for="item,index in dataList" :key="item?.id||index">
        <!-- 具体内容 -->
    </swiper-item>
</b-swiper>
回到顶部