Detailed explanation of the error when using Element-ui NavMenu submenu to generate recursively

Detailed explanation of the error when using Element-ui NavMenu submenu to generate recursively

When the submenu of the navigation bar is generated recursively, the menu can be generated normally, but when the mouse is hovered, a certain (mouseenter) event will be called cyclically, resulting in an error in the end

Processing

Note: In version 2.13.2, you only need to set the attribute of the submenu: popper-append-to-body="false" to avoid this problem.

The error message is as follows:

Uncaught RangeError: Maximum call stack size exceeded.
at VueComponent.handleMouseenter (index.js:1)
at invokeWithErrorHandling (vue.js:1863)
at HTMLLIElement.invoker (vue.js:2188)
at HTMLLIElement.original._wrapper (vue.js:7547)
at VueComponent.handleMouseenter (index.js:1)
at invokeWithErrorHandling (vue.js:1863)
at HTMLLIElement.invoker (vue.js:2188)
at HTMLLIElement.original._wrapper (vue.js:7547)
at VueComponent.handleMouseenter (index.js:1)
at invokeWithErrorHandling (vue.js:1863)

Test code

Version:

  • vue: v2.6.11
  • element-ui: 2.13.0
<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
  <title></title>
  <!-- Import style -->
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" rel="external nofollow" >
 </head>
 <body>

  <div id="root">
   <el-menu mode="horizontal">
    <template v-for="(menu,index) in menus">
     <sub-menu v-if="menu.children && menu.children.length" :key="index" :item="menu"></sub-menu>
     <el-menu-item v-else :index="menu.path" :key="index">{{ menu.title }}</el-menu-item>
    </template>
   </el-menu>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <!-- Import component library-->
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script type="text/javascript">
   Vue.component('sub-menu', {
    props: ['item'],
    template: `
     <el-submenu :index="item.path">
      <template slot="title">
       {{item.title}}
      </template>
      <template v-for="(child,index) in item.children">
       <sub-menu v-if="child.children" :item="child" :key="index"></sub-menu>
       <el-menu-item v-else :key="index" :index="child.path">
        {{child.title}}
       </el-menu-item>
      </template>
     </el-submenu>
    `
   })

   let vm = new Vue({
    el: '#root',
    data() {
     return {
      menus: [{
       title: 'My Workbench',
       path: '2',
       children: [{
         title: 'Option 1',
         path: '2-1'
        },
        {
         title: 'Option 2',
         path: '2-2',
        },
       ],
      },{
       title:'Background Management',
       path:'3'
      }]
     }
    },
    components: {}
   })
  </script>
 </body>
</html>

Error Analysis

Observe the recursively generated navigation bar code and error code:

 handleMouseenter: function(e) {
                    var t = this
                      , i = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : this.showTimeout;
                    if ("ActiveXObject" in window || "focus" !== e.type || e.relatedTarget) {
                        var n = this.rootMenu
                          , r = this.disabled;
                        "click" === n.menuTrigger && "horizontal" === n.mode || !n.collapse && "vertical" === n.mode || r || (this.dispatch("ElSubmenu", "mouse-enter-child"),
                        clearTimeout(this.timeout),
                        this.timeout = setTimeout(function() {
                            t.rootMenu.openMenu(t.index, t.indexPath)
                        }, i),
                        this.appendToBody && this.$parent.$el.dispatchEvent(new MouseEvent("mouseenter")));//Error code}
                },

I guess it's because the event bubbling or sinking causes the element to repeatedly dispatch and receive mouseenter events, resulting in a state similar to an infinite loop. Due to time constraints, I didn't go into it in depth. I'll check the root cause later when I have time (if I remember...)

When the mouse moves into the menu, the handleMouseenter method is triggered, but because appendToBody is true, the mouse enter event is dispatched again, and then returns to this method, resulting in an infinite loop. appendToBody is a calculated property, so why is appendToBody true? Look at the code:

{
 name: 'ElSubmenu',
    componentName: 'ElSubmenu',
 props:{
  popperAppendToBody: {
         type: Boolean,
         default: undefined   
        }
    },
    computed:{
  appendToBody() {
        return this.popperAppendToBody === undefined     
          ? this.isFirstLevel //When popperAppendToBody is not explicitly specified, calculate this value: this.popperAppendToBody;
      },
      isFirstLevel() {
        let isFirstLevel = true;
        let parent = this.$parent;
        while (parent && parent !== this.rootMenu) {
        
        //Calculate whether the current menu is the first level.
        //It seems to be OK, because the code has specified that the current component name is componentName: 'ElSubmenu', but during debugging, it was found that the value of componentName is Undefined, so no matter which level it is, the final result is isFirstLevel = true 
          if (['ElSubmenu', 'ElMenuItemGroup'].indexOf(parent.$options.componentName) > -1) {
            isFirstLevel = false;
            break;
          } else {
            parent = parent.$parent;
          }
        }
        return isFirstLevel;
      }
 }
}

As for why Vue did not collect this parameter when registering the component, we still need to look at the source code. The lunch break is over, and I have to continue to code... I will analyze it again when I have time...

Processing

Add an attribute to el-submenu: popper-append-to-body="true false" to explicitly specify appendToBody as false

Special apologies:

The previous processing method was written incorrectly. It was written as: popper-append-to-body="true". Therefore, even if this attribute is added, an error is still reported. I apologize for this!

This is the end of this article about the detailed explanation of the error when using recursive generation of Element-ui NavMenu submenu. For more relevant content about recursive generation of Element-ui NavMenu submenu, please search for previous articles on 123WORDPRESS.COM or continue to browse the related articles below. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Solution for highlighting the vue+element navigation bar
  • Element-Ui component NavMenu specific use of navigation menu
  • Solve the problem that the navigation menu is highlighted in the wrong position after refreshing the Vue project
  • Solve the problem of highlighting the NavMenu navigation menu in elementui (solve multiple situations)

<<:  Detailed example of MySQL data storage process parameters

>>:  VMware Workstation 14 Pro installs CentOS 7.0

Recommend

Detailed explanation of BOM and DOM in JavaScript

Table of contents BOM (Browser Object Model) 1. W...

Detailed graphic tutorial on installing centos7 virtual machine in Virtualbox

1. Download centos7 Download address: https://mir...

CentOS 6.5 configuration ssh key-free login to execute pssh command explanation

1. Check and install pssh, yum list pssh 2. Becau...

How to avoid data loop conflicts when MySQL is configured with dual masters

I wonder if you have ever thought about this ques...

Definition and function of zoom:1 attribute in CSS

Today I was asked what the zoom attribute in CSS ...

Three ways to parse QR codes using javascript

Table of contents 1. Use JavaScript to parse the ...

Ubuntu 20.04 how to modify the IP address example

illustrate: Today, when continuing the last offic...

CSS realizes the layout method of fixed left and adaptive right

1. Floating layout 1. Let the fixed width div flo...

WeChat applet implements calculator function

WeChat Mini Programs are becoming more and more p...

Windows Server 2016 Quick Start Guide to Deploy Remote Desktop Services

Now 2016 server supports multi-site https service...

Detailed explanation of the solution to font blur when using transform in CSS3

This question is very strange, so I will go strai...

Connector configuration in Tomcat

JBoss uses Tomcat as the Web container, so the co...

Vue custom encapsulated button component

The custom encapsulation code of the vue button c...