element icon indicating copy to clipboard operation
element copied to clipboard

[Bug Report] El-submenu causes 'Maximum call stack exceeded' error in collapsed menu if it's the top element of a component

Open mik-jozef opened this issue 4 years ago • 13 comments

Element UI version

2.12.0

OS/Browsers version

Windows 10 OS Version 1809 (Build 17763.805) / 78.0.3904.70 (Official Build) (64-bit) (cohort: 78_70_Win)

Vue version

2.6.10

Reproduction Link

https://codepen.io/mik-jozef-artin/pen/abbYNza

Steps to reproduce

  1. Open the reproduction link.
  2. Place mouse on the menu (ie. the text 'title')

The error 'Maximum call stack size exceeded' will appear in the console.

It seems to me that these conditions are all necessary for the issue to manifest:

  1. Menu must be collapsed (the collapse prop on el-menu must be true)
  2. Submenu must be in a separate component (in this case customized-menu-item)
  3. The submenu must be the top element in the separate component.
  4. Attribute :popper-append-to-body="true" must be present on the submenu

Fortunately, the second condition provides an easy workaround - placing the submenu inside a div will suppress the issue. This behavior is still surprising and I guess unwanted.

What is Expected?

No errors.

What is actually happening?

Uncaught RangeError: Maximum call stack size exceeded.

mik-jozef avatar Nov 05 '19 16:11 mik-jozef

same issue!

zhyy2008z avatar Jan 02 '20 14:01 zhyy2008z

@element-bot 希望可以修复这个问题 应用场景还是蛮多的

SmileAjh avatar Jan 13 '20 02:01 SmileAjh

same issue

larrykkk avatar Jan 22 '20 06:01 larrykkk

mark

9-lives avatar May 22 '20 02:05 9-lives

I fixed this bug by rewirte method "handleMouseenter" of el-submenu in self-module . (sorry for the format, I can't fix it.)

The easiest way is setting :popper-append-to-body="false" . If you have to append to body, you can try the follow code :

mounted() { let redefine_el_submenu_handleMouseenter = function (event) { // ignore some original handleMouseenter code, please parse by yourself.//
if (this.appendToBody && this.$parent.$el !== event.target) { this.$parent.$el.dispatchEvent(new MouseEvent('mouseenter')); } } this.$children[0].handleMouseenter = (event) => { redefine_el_submenu_handleMouseenter.call(this.$children[0], event) } }

gaopengpian avatar Jun 04 '20 08:06 gaopengpian

same issue

yushko2015 avatar Jul 13 '20 14:07 yushko2015

hope fix it ~~

kyleqqq avatar Sep 17 '20 02:09 kyleqqq

Still unfixed oficially

sintro avatar Jan 13 '21 17:01 sintro

出问题代码 SideBarMenu/index.vue代码:

<template>
    <el-menu
        :collapse="closedSideBar"
        background-color=""
        text-color=""
        active-text-color=""
        :default-active="'/home'"
        router
    >
        <side-bar-menu-item
            v-for="(routeItem, index) in routeList"
            :key="index"
            :route-item="routeItem"
        ></side-bar-menu-item>
    </el-menu>
</template>

<script>
import SideBarMenuItem from "./components/SideBarMenuItem";
import mixins from "../mixins";
export default {
    name: "SideBarMenu",
    mixins: [mixins],
    components: {
        SideBarMenuItem,
    },
    data() {
        return {
            routeList: [
                { path: "/home", title: "路由1" },
                {
                    path: "2",
                    title: "路由2",
                    children: [
                        { path: "/about", title: "路由2-1" },
                        {
                            path: "2-2",
                            title: "路由2-2",
                            children: [{ path: "2-2-1", title: "路由2-2-1" }],
                        },
                    ],
                },
            ],
        };
    },
};
</script>

<style lang="scss" scoped>
.el-menu {
    border: none;
}
</style>

SideBarMenu/components/SideBarMenuItem/index.vue代码:

<template>
    <el-submenu v-if="routeItem.children && routeItem.children.length" :index="routeItem.path">
        <template #title>
            <i class="el-icon-menu"></i>
            <span>{{ routeItem.title }}</span>
        </template>
        <side-bar-menu-item
            v-for="(item, index) in routeItem.children"
            :key="index"
            :route-item="item"
        ></side-bar-menu-item>
    </el-submenu>
    <el-menu-item v-else :index="routeItem.path">
        <i class="el-icon-menu"></i>
        <template #title>
            <span>{{ routeItem.title }}</span>
        </template>
    </el-menu-item>
</template>

<script>
export default {
    name: "SideBarMenuItem",
    props: {
        routeItem: {
            type: Object,
        },
    },
};
</script>

解决方案: 直接使用渲染函数渲染本问题可以完美解决

import Vue from "vue";
import mixins from "../mixins";

const createSideBarMenuItem = (createElement, routeList) => {
    return routeList.map((routeItem) => {
        if (routeItem.children && routeItem.children.length) {
            return createElement(
                "el-submenu",
                {
                    props: {
                        index: routeItem.path,
                    },
                },
                [
                    createElement(
                        "template",
                        {
                            slot: "title",
                        },
                        [
                            createElement("i", {
                                class: "el-icon-menu",
                            }),
                            createElement("span", {
                                domProps: {
                                    innerHTML: routeItem.title,
                                },
                            }),
                        ]
                    ),
                    createSideBarMenuItem(createElement, routeItem.children),
                ]
            );
        } else {
            return createElement(
                "el-menu-item",
                {
                    props: {
                        index: routeItem.path,
                    },
                },
                [
                    createElement("i", {
                        class: "el-icon-menu",
                    }),
                    createElement("span", {
                        slot: "title",
                        domProps: {
                            innerHTML: routeItem.title,
                        },
                    }),
                ]
            );
        }
    });
};

const SideBarMenu = Vue.component("SideBarMenu", {
    render(createElement) {
        return createElement(
            "el-menu",
            {
                style: {
                    border: "none",
                },
                mixins: [mixins],
                props: {
                    router: true,
                    collapse: this.closedSideBar,
                },
            },
            createSideBarMenuItem(createElement, this.routeList)
        );
    },
    props: {
        routeList: {
            type: Array,
            default: () => [
                { path: "/home", title: "路由1" },
                {
                    path: "2",
                    title: "路由2",
                    children: [
                        { path: "/about", title: "路由2-1" },
                        {
                            path: "2-2",
                            title: "路由2-2",
                            children: [{ path: "2-2-1", title: "路由2-2-1" }],
                        },
                    ],
                },
            ],
        },
        closedSideBar: {
            type: Boolean,
            default: true,
        },
    },
});

export default SideBarMenu;

qiuqfang avatar Jan 15 '21 07:01 qiuqfang

this.$parent.$el !== event.target

It's always true on my side

feiyu1995 avatar May 06 '21 06:05 feiyu1995

https://blog.csdn.net/qq_34452824/article/details/106546478
fix it by hack, but it,s not very good

huozhenzhen avatar Aug 05 '21 06:08 huozhenzhen

+1

fratzinger avatar Sep 01 '21 14:09 fratzinger

+1

profispojka avatar Sep 15 '22 05:09 profispojka

有一个不钳充钱就能玩的游戏,http://www.0vslu5.cn ,听说信用很好的,我们去玩两把吧,反正没有风险。<狄/p>

huozhenzhen avatar Sep 15 '22 05:09 huozhenzhen

我也遇到了。 目前在网上找到两个方法: 1.外层添加div包裹 2.popper-append-to-body设置为false 但是两种解决方案,都会导致其他副作用。还望官方能够修复下..

lwm98 avatar Sep 16 '22 08:09 lwm98