额外的非props属性(名称)被传递给组件,但无法自动继承,因为组件呈现片段或文本根节点?

这个页面一直提示上面的错误。

<template>
    <header class="ruyuan_header fixed left-0 right-0 top-0 z-[99] h-[70px] bg-[#ffffff]">
        <div
            class="flex items-center justify-between bg-[#ffffff] p-[5px] xl:relative xl:z-[98] xl:mx-auto xl:flex xl:h-[70px] xl:max-w-[1200px] xl:items-center xl:bg-[#ffffff] xl:max-md:px-4"
        >
            <div class="wow animate_animated animate__fadeInLeft">
                <a href="javascript:void(0)" class="ruyuan_wrap_icon block h-[60px] w-[152px]"></a>
            </div>
            <div class="wow animate_animated animate__fadeInRight cursor-pointer xl:ml-[170px]">
                <div class="xl:hidden" @click="isShowDrawer = true">
                    <Icon type="md-menu" size="32" color="#e4040e" />
                </div>
                <ul class="hidden xl:flex">
                    <li v-for="(item, index) in bannerArray" :key="index" class="ruyuan_wrap_box">
                        <Dropdown>
                            <NuxtLink :to="item.route" :class="['ruyuan_wrap_link']"> 1{{ item.label }} </NuxtLink>
                            <template #list>
                                <DropdownMenu
                                    v-for="(Iitem, Iindex) in item.child"
                                    :key="Iindex"
                                    :class="['ruyuan_wrap_list']"
                                >
                                    <DropdownItem
                                        ><NuxtLink class="ruyuan_wrap_item" :to="Iitem.route"
                                            >2{{ Iitem.label }}</NuxtLink
                                        ><template #list>
                                            <DropdownMenu
                                                v-for="(Iitem, Iindex) in item.child"
                                                :key="Iindex"
                                                :class="['ruyuan_wrap_list']"
                                            >
                                                <DropdownItem
                                                    ><NuxtLink class="ruyuan_wrap_item" :to="Iitem.route"
                                                        >2{{ Iitem.label }}</NuxtLink
                                                    ></DropdownItem
                                                >
                                            </DropdownMenu>
                                        </template>
                                    </DropdownItem>
                                </DropdownMenu>
                            </template>
                        </Dropdown>
                    </li>
                </ul>
                <Drawer
                    placement="right"
                    v-model="isShowDrawer"
                    :closable="false"
                    width="60"
                    class-name="ruyuan_drawer"
                >
                    <Menu accordion @on-open-change="handleMenuChange" width="60">
                        <div class="flex h-[35px] items-center bg-[#e4040e] pl-[10px]" @click="isShowDrawer = false">
                            <img src="../assets/image/close.png" alt="" />
                        </div>
                        <Submenu v-for="(item, index) in bannerArray" :key="index" :name="index + ''">
                            <template #title>
                                <div
                                    class="flex h-[40px] items-center justify-between border-b border-[#e4040e] pb-[30px] pt-[35px]"
                                >
                                    <NuxtLink
                                        :to="item.route"
                                        class="text-[15px] text-[#e4040e]"
                                        @click="handleClickItem"
                                        >{{ item.label }}
                                    </NuxtLink>
                                    <span v-if="item.child">
                                        <span
                                            :class="[
                                                isShowMeun == true && itemIndex == index ? 'hidden' : 'block',
                                                'text-[20px]',
                                                'text-[#e4040e]',
                                            ]"
                                            >+</span
                                        >
                                        <span
                                            :class="[
                                                isShowMeun == true && itemIndex == index ? 'block' : 'hidden',
                                                'text-[20px]',
                                                'text-[#e4040e]',
                                            ]"
                                            >-</span
                                        >
                                    </span>
                                    <img
                                        v-else
                                        src="../assets/image/arrow.png"
                                        alt=""
                                        class="inline-block h-[15px] w-[8px]"
                                    />
                                </div>
                            </template>
                            <MenuItem
                                v-for="(Iitem, Iindex) in item.child"
                                :key="Iindex"
                                :to="Iitem.route"
                                @click="handleClickItem"
                            >
                                <div class="tems-center flex justify-between">
                                    <span class="text-[15px] text-[#e4040e]">{{ Iitem.label }}</span
                                    ><img
                                        src="../assets/image/arrow.png"
                                        alt=""
                                        class="inline-block h-[14px] w-[8px]"
                                    />
                                </div>
                            </MenuItem>
                        </Submenu>
                    </Menu>
                </Drawer>
            </div>
        </div>

        <!-- route.path.includes(item.route) ? 'ruyuan_wrap_active' : '','ruyuan_wrap_link', -->
        <!-- :class="handleRouter(item.route)" -->
    </header>
</template>

<script setup>
import { useRoute, useRouter } from 'vue-router';
const router = useRouter();
const route = useRoute();
// 导航数据及路由
const bannerArray = [
    {
        value: 0,
        label: '首页',
        route: '/',
    },
    {
        value: 1,
        label: '关于入园奶',
        route: '/about',
        child: [
            {
                value: 0,
                label: '品牌故事',
                route: '/about',
                child: [
                    {
                        value: 0,
                        label: '品牌故事',
                        route: '/about',
                    },
                ],
            },
            {
                value: 1,
                label: '品牌理念',
                route: '/about/notion',
            },
            {
                value: 2,
                label: '品牌文化',
                route: '/about/culture',
            },
        ],
    },
    {
        value: 2,
        label: '产品品质',
        route: '/product',
        child: [
            {
                value: 0,
                label: '安全体系',
                route: '/product',
            },
            {
                value: 1,
                label: '严格品控',
                route: '/product/control',
            },
        ],
    },
    {
        value: 3,
        label: '品牌产品',
        route: '/brand',
        child: [
            {
                value: 0,
                label: '入园壮',
                route: '/brand',
            },
            {
                value: 1,
                label: '倍乐高',
                route: '/brand/lego',
            },
        ],
    },
    {
        value: 4,
        label: '新闻活动',
    },
    {
        value: 5,
        label: '正品购买',
    },
    {
        value: 6,
        label: '产品追溯',
    },
];

// 弹出/关闭抽屉
let isShowDrawer = ref();
isShowDrawer.value = false;

// 控制展示+ -号出现1
let isShowMeun = ref();
isShowMeun.value = false;

// 控制展示+ -号出现2
let itemIndex = ref();
itemIndex.value = '-1';

// 控制展示+ -号出现3
function handleMenuChange(value) {
    if (value == '1' || value == '2' || value == '3') {
        isShowMeun = true;
        itemIndex = value;
    } else {
        isShowMeun = false;
    }
}

// 点击导航跳转以后 把导航菜单关闭
function handleClickItem() {
    if (isShowDrawer.value) {
        isShowDrawer.value = false;
    } else {
        isShowDrawer.value = true;
    }
}

const plusMinusClass = computed(() => (index) => [
    isShowMeun && itemIndex == index ? 'hidden' : 'block',
    'text-[20px]',
    'text-[#e4040e]',
]);
</script>

<style lang="less" scoped>
.ruyuan {
    &_wrap {
        &_icon {
            margin-right: 10px;
            background: url(../assets/image/logo.png) no-repeat 50% / contain;
        }
        &_box {
            margin-right: 30px;
        }
        &_link {
            display: inline-block;
            width: 100px;
            height: 70px;
            line-height: 70px;
            text-align: center;
            font-size: 18px;
            color: #555555;
            //background: url(../assets/image/icon.png) no-repeat 50% / contain;
            background-size: 30px 37px;
        }

        &_link:hover,
        &_active {
            color: #000000;
            //background: url(../assets/image/icon-h.png) no-repeat 50% / contain #e4040e;
            background-size: 30px 37px;
        }

        &_list .ivu-dropdown-item {
            text-align: center !important;
        }
        &_list .ivu-dropdown-item:hover,
        &_active .ivu-dropdown-item {
            background-color: #e4040e;
            color: #ffffff;
        }
        &_list &_item {
            font-size: 15px;
            color: #e4040e;
        }
        &_active .ivu-dropdown-item &_item,
        &_list .ivu-dropdown-item:hover &_item {
            color: #ffffff;
        }
    }
}
</style>
<style>
.ruyuan_drawer .ivu-drawer-body {
    padding: 0 !important;
    overflow: hidden;
}
.ruyuan_drawer .ivu-icon-ios-arrow-down:before {
    content: '';
}
.ruyuan_drawer .ivu-menu-vertical .ivu-menu-submenu-title {
    padding: 0 24px;
}

.ruyuan_drawer .ivu-menu-vertical .ivu-menu-item:last-child {
    border-bottom: 1px solid #e4040e !important;
}
.ruyuan_drawer .ivu-menu .ivu-menu-light .ivu-menu-vertical {
    width: 0 !important;
}
.ruyuan_drawer .ivu-menu-light.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu) {
    background-color: #ffffff !important;
}
.ruyuan_drawer .ivu-menu-light.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu):after {
    content: '' !important;
    display: none !important;
}
</style>
阅读 575
avatarAI BotBETA

这个错误通常发生在你尝试将非props属性传递给一个Vue组件,但这个组件的根节点是一个片段(fragment)或纯文本节点,导致Vue无法将额外的属性自动应用到任何具体的DOM元素上。在Vue中,只有组件的根元素可以接收非props属性(如classstyle等),并将它们应用到DOM上。

解决方案

  1. 检查并修改组件定义
    确保你正在使用的自定义组件(如DropdownDropdownMenuDropdownItem等)能够处理或至少忽略传递给它们的额外属性。如果可能,更新这些组件的模板,使其有一个可以接收属性的根元素。
  2. 使用$attrs$listeners
    如果你不能修改这些组件的源代码,你可以在组件内部使用$attrs来接收所有非props的属性,并手动将它们应用到某个元素上。同样,使用$listeners可以处理所有传入的事件监听器。

    <template>
      <div v-bind="$attrs">
        <!-- 组件的其他内容 -->
      </div>
    </template>
    
    <script>
    export default {
      inheritAttrs: false, // 防止自动绑定到根元素
      // ... 其他选项
    }
    </script>

注意:设置inheritAttrs: false是为了防止Vue自动将$attrs绑定到组件的根元素上,这样你就可以控制哪些元素应该接收这些属性。

  1. 修改模板以避免传递非必要属性
    如果可能,修改你的模板,避免将不必要的属性传递给不需要它们的组件。这可以通过条件渲染或计算属性来实现。
  2. 使用包装元素
    如果上述方法都不可行,你可以考虑在你的模板中添加一个包装元素(如<div>),并将所有非props属性绑定到这个包装元素上。这虽然可能会增加DOM的层级,但可以作为临时解决方案。

示例

假设Dropdown组件的模板当前没有根元素或根元素无法接收属性,你可以这样修改你的模板:

<div v-bind="$attrs">
  <Dropdown>
    <!-- Dropdown 的内容 -->
  </Dropdown>
</div>

这样,所有传递给Dropdown的额外属性都会被绑定到这个新的<div>元素上。注意,这种方法可能会影响到CSS样式或布局,因此请确保它符合你的设计需求。

1 个回答

我做了以下修改
1.确保所有传递的属性都是组件所期望的:
在 DropdownMenu 和 DropdownItem 组件中添加了 v-if 条件,以确保只有在存在子项时才渲染这些组件。
2.修复 v-model 绑定:
将 v-model 改为 v-model:visible 以确保正确绑定 Drawer 组件的可见性。
3.修复 plusMinusClass 计算属性:
确保 plusMinusClass 计算属性正确返回类名数组。

<template>
    <header class="ruyuan_header fixed left-0 right-0 top-0 z-[99] h-[70px] bg-[#ffffff]">
        <div
            class="flex items-center justify-between bg-[#ffffff] p-[5px] xl:relative xl:z-[98] xl:mx-auto xl:flex xl:h-[70px] xl:max-w-[1200px] xl:items-center xl:bg-[#ffffff] xl:max-md:px-4"
        >
            <div class="wow animate_animated animate__fadeInLeft">
                <a href="javascript:void(0)" class="ruyuan_wrap_icon block h-[60px] w-[152px]"></a>
            </div>
            <div class="wow animate_animated animate__fadeInRight cursor-pointer xl:ml-[170px]">
                <div class="xl:hidden" @click="isShowDrawer = true">
                    <Icon type="md-menu" size="32" color="#e4040e" />
                </div>
                <ul class="hidden xl:flex">
                    <li v-for="(item, index) in bannerArray" :key="index" class="ruyuan_wrap_box">
                        <Dropdown>
                            <NuxtLink :to="item.route" :class="['ruyuan_wrap_link']">{{ item.label }}</NuxtLink>
                            <template #list>
                                <DropdownMenu v-if="item.child" v-for="(childItem, childIndex) in item.child" :key="childIndex" :class="['ruyuan_wrap_list']">
                                    <DropdownItem>
                                        <NuxtLink class="ruyuan_wrap_item" :to="childItem.route">{{ childItem.label }}</NuxtLink>
                                        <template #list>
                                            <DropdownMenu v-if="childItem.child" v-for="(subChildItem, subChildIndex) in childItem.child" :key="subChildIndex" :class="['ruyuan_wrap_list']">
                                                <DropdownItem>
                                                    <NuxtLink class="ruyuan_wrap_item" :to="subChildItem.route">{{ subChildItem.label }}</NuxtLink>
                                                </DropdownItem>
                                            </DropdownMenu>
                                        </template>
                                    </DropdownItem>
                                </DropdownMenu>
                            </template>
                        </Dropdown>
                    </li>
                </ul>
                <Drawer
                    placement="right"
                    v-model:visible="isShowDrawer"
                    :closable="false"
                    width="60"
                    class-name="ruyuan_drawer"
                >
                    <Menu accordion @on-open-change="handleMenuChange" width="60">
                        <div class="flex h-[35px] items-center bg-[#e4040e] pl-[10px]" @click="isShowDrawer = false">
                            <img src="../assets/image/close.png" alt="" />
                        </div>
                        <Submenu v-for="(item, index) in bannerArray" :key="index" :name="index + ''">
                            <template #title>
                                <div
                                    class="flex h-[40px] items-center justify-between border-b border-[#e4040e] pb-[30px] pt-[35px]"
                                >
                                    <NuxtLink
                                        :to="item.route"
                                        class="text-[15px] text-[#e4040e]"
                                        @click="handleClickItem"
                                        >{{ item.label }}
                                    </NuxtLink>
                                    <span v-if="item.child">
                                        <span
                                            :class="plusMinusClass(index)"
                                            >+</span
                                        >
                                        <span
                                            :class="plusMinusClass(index)"
                                            >-</span
                                        >
                                    </span>
                                    <img
                                        v-else
                                        src="../assets/image/arrow.png"
                                        alt=""
                                        class="inline-block h-[15px] w-[8px]"
                                    />
                                </div>
                            </template>
                            <MenuItem
                                v-for="(childItem, childIndex) in item.child"
                                :key="childIndex"
                                :to="childItem.route"
                                @click="handleClickItem"
                            >
                                <div class="tems-center flex justify-between">
                                    <span class="text-[15px] text-[#e4040e]">{{ childItem.label }}</span
                                    ><img
                                        src="../assets/image/arrow.png"
                                        alt=""
                                        class="inline-block h-[14px] w-[8px]"
                                    />
                                </div>
                            </MenuItem>
                        </Submenu>
                    </Menu>
                </Drawer>
            </div>
        </div>
    </header>
</template>

<script setup>
import { ref, computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';

const router = useRouter();
const route = useRoute();

const bannerArray = [
    {
        value: 0,
        label: '首页',
        route: '/',
    },
    {
        value: 1,
        label: '关于入园奶',
        route: '/about',
        child: [
            {
                value: 0,
                label: '品牌故事',
                route: '/about',
                child: [
                    {
                        value: 0,
                        label: '品牌故事',
                        route: '/about',
                    },
                ],
            },
            {
                value: 1,
                label: '品牌理念',
                route: '/about/notion',
            },
            {
                value: 2,
                label: '品牌文化',
                route: '/about/culture',
            },
        ],
    },
    {
        value: 2,
        label: '产品品质',
        route: '/product',
        child: [
            {
                value: 0,
                label: '安全体系',
                route: '/product',
            },
            {
                value: 1,
                label: '严格品控',
                route: '/product/control',
            },
        ],
    },
    {
        value: 3,
        label: '品牌产品',
        route: '/brand',
        child: [
            {
                value: 0,
                label: '入园壮',
                route: '/brand',
            },
            {
                value: 1,
                label: '倍乐高',
                route: '/brand/lego',
            },
        ],
    },
    {
        value: 4,
        label: '新闻活动',
    },
    {
        value: 5,
        label: '正品购买',
    },
    {
        value: 6,
        label: '产品追溯',
    },
];

// 弹出/关闭抽屉
let isShowDrawer = ref(false);

// 控制展示+ -号出现1
let isShowMeun = ref(false);

// 控制展示+ -号出现2
let itemIndex = ref('-1');

// 控制展示+ -号出现3
function handleMenuChange(value) {
    if (value == '1' || value == '2' || value == '3') {
        isShowMeun.value = true;
        itemIndex.value = value;
    } else {
        isShowMeun.value = false;
    }
}

// 点击导航跳转以后 把导航菜单关闭
function handleClickItem() {
    isShowDrawer.value = !isShowDrawer.value;
}

const plusMinusClass = computed(() => (index) => [
    isShowMeun.value && itemIndex.value == index ? 'hidden' : 'block',
    'text-[20px]',
    'text-[#e4040e]',
]);
</script>

<style lang="less" scoped>
.ruyuan {
    &_wrap {
        &_icon {
            margin-right: 10px;
            background: url(../assets/image/logo.png) no-repeat 50% / contain;
        }
        &_box {
            margin-right: 30px;
        }
        &_link {
            display: inline-block;
            width: 100px;
            height: 70px;
            line-height: 70px;
            text-align: center;
            font-size: 18px;
            color: #555555;
            background-size: 30px 37px;
        }

        &_link:hover,
        &_active {
            color: #000000;
            background-size: 30px 37px;
        }

        &_list .ivu-dropdown-item {
            text-align: center !important;
        }
        &_list .ivu-dropdown-item:hover,
        &_active .ivu-dropdown-item {
            background-color: #e4040e;
            color: #ffffff;
        }
        &_list &_item {
            font-size: 15px;
            color: #e4040e;
        }
        &_active .ivu-dropdown-item &_item,
        &_list .ivu-dropdown-item:hover &_item {
            color: #ffffff;
        }
    }
}
</style>

<style>
.ruyuan_drawer .ivu-drawer-body {
    padding: 0 !important;
    overflow: hidden;
}
.ruyuan_drawer .ivu-icon-ios-arrow-down:before {
    content: '';
}
.ruyuan_drawer .ivu-menu-vertical .ivu-menu-submenu-title {
    padding: 0 24px;
}

.ruyuan_drawer .ivu-menu-vertical .ivu-menu-item:last-child {
    border-bottom: 1px solid #e4040e !important;
}
.ruyuan_drawer .ivu-menu .ivu-menu-light .ivu-menu-vertical {
    width: 0 !important;
}
.ruyuan_drawer .ivu-menu-light .ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu) {
    background-color: #ffffff !important;
}
.ruyuan_drawer .ivu-menu-light .ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu):after {
    content: '' !important;
    display: none !important;
}
</style>
宣传栏