• 售前

  • 售后

热门帖子
入门百科

详解Element-ui NavMenu子菜单使用递归天生时使用报错

[复制链接]
yfyffuuy 显示全部楼层 发表于 2021-10-26 14:10:15 |阅读模式 打印 上一主题 下一主题
当接纳递归方式生成导航栏的子菜单时,菜单可以正常生成,但是当鼠标hover时,会出现循环调用某个(mouseenter)事件,导致最后报错

处置惩罚方式


注:2.13.2 版本,只需对子菜单设置属性 :popper-append-to-body="false" 就不会出现这个题目了
报错信息如下:

  1. Uncaught RangeError: Maximum call stack size exceeded.
  2.     at VueComponent.handleMouseenter (index.js:1)
  3.     at invokeWithErrorHandling (vue.js:1863)
  4.     at HTMLLIElement.invoker (vue.js:2188)
  5.     at HTMLLIElement.original._wrapper (vue.js:7547)
  6.     at VueComponent.handleMouseenter (index.js:1)
  7.     at invokeWithErrorHandling (vue.js:1863)
  8.     at HTMLLIElement.invoker (vue.js:2188)
  9.     at HTMLLIElement.original._wrapper (vue.js:7547)
  10.     at VueComponent.handleMouseenter (index.js:1)
  11.     at invokeWithErrorHandling (vue.js:1863)
复制代码
测试代码


版本:
       
  • vue: v2.6.11   
  • element-ui: 2.13.0
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.   <meta charset="utf-8">
  5.   <title></title>
  6.   <!-- 引入样式 -->
  7.   <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" rel="external nofollow" >
  8. </head>
  9. <body>
  10.   <div id="root">
  11.    <el-menu mode="horizontal">
  12.     <template v-for="(menu,index) in menus">
  13.      <sub-menu v-if="menu.children && menu.children.length" :key="index" :item="menu"></sub-menu>
  14.      <el-menu-item v-else :index="menu.path" :key="index">{{ menu.title }}</el-menu-item>
  15.     </template>
  16.    </el-menu>
  17.   </div>
  18.   <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  19.   <!-- 引入组件库 -->
  20.   <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  21.   <script type="text/javascript">
  22.    Vue.component('sub-menu', {
  23.     props: ['item'],
  24.     template: `
  25.      <el-submenu :index="item.path">
  26.       <template slot="title">
  27.        {{item.title}}
  28.       </template>
  29.       <template v-for="(child,index) in item.children">
  30.        <sub-menu v-if="child.children" :item="child" :key="index"></sub-menu>
  31.        <el-menu-item v-else :key="index" :index="child.path">
  32.         {{child.title}}
  33.        </el-menu-item>
  34.       </template>
  35.      </el-submenu>
  36.     `
  37.    })
  38.    let vm = new Vue({
  39.     el: '#root',
  40.     data() {
  41.      return {
  42.       menus: [{
  43.        title: '我的工作台',
  44.        path: '2',
  45.        children: [{
  46.          title: '选项1',
  47.          path: '2-1'
  48.         },
  49.         {
  50.          title: '选项2',
  51.          path: '2-2',
  52.         },
  53.        ],
  54.       },{
  55.        title:'后台管理',
  56.        path:'3'
  57.       }]
  58.      }
  59.     },
  60.     components: {}
  61.    })
  62.   </script>
  63. </body>
  64. </html>
复制代码
错误分析


观察递归生成的导航栏代码及报错代码:
  1. handleMouseenter: function(e) {
  2.                     var t = this
  3.                       , i = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : this.showTimeout;
  4.                     if ("ActiveXObject"in window || "focus" !== e.type || e.relatedTarget) {
  5.                         var n = this.rootMenu
  6.                           , r = this.disabled;
  7.                         "click" === n.menuTrigger && "horizontal" === n.mode || !n.collapse && "vertical" === n.mode || r || (this.dispatch("ElSubmenu", "mouse-enter-child"),
  8.                         clearTimeout(this.timeout),
  9.                         this.timeout = setTimeout(function() {
  10.                             t.rootMenu.openMenu(t.index, t.indexPath)
  11.                         }, i),
  12.                         this.appendToBody && this.$parent.$el.dispatchEvent(new MouseEvent("mouseenter")));//报错代码
  13.                     }
  14.                 },
复制代码
推测是由于事件冒泡或下沉导致元素重复派发和担当mouseenter事件,造成了类似死循环的状态,因时间关系,没做深究,背面偶然间的时候再查下根本缘故原由(如果记得的话…)

当鼠标移入到菜单中时,触发handleMouseenter方法,但是由于appendToBody为true,以是又派发了鼠标移入事件,然后又回到了这个方法,由此造成了死循环。appendToBody是一个计算属性,那么为什么appendToBody会是true呢?看代码:
  1. {
  2. name: 'ElSubmenu',
  3.     componentName: 'ElSubmenu',
  4. props:{
  5.   popperAppendToBody: {
  6.          type: Boolean,
  7.          default: undefined   
  8.         }
  9.     },
  10.     computed:{
  11.   appendToBody() {
  12.         return this.popperAppendToBody === undefined     
  13.           ? this.isFirstLevel              //未显示指明popperAppendToBody 时,计算这个值
  14.           : this.popperAppendToBody;
  15.       },
  16.       isFirstLevel() {
  17.         let isFirstLevel = true;
  18.         let parent = this.$parent;
  19.         while (parent && parent !== this.rootMenu) {
  20.         
  21.         //计算当前是否时第一级菜单。
  22.         //看上去是没问题的,因为代码里已经指明了当前的组件名是 componentName: 'ElSubmenu', 但是在调试中发现,componentName的值是Undefined, 因此不管是在哪一级,最后的结果都是 isFirstLevel = true
  23.           if (['ElSubmenu', 'ElMenuItemGroup'].indexOf(parent.$options.componentName) > -1) {
  24.             isFirstLevel = false;
  25.             break;
  26.           } else {
  27.             parent = parent.$parent;
  28.           }
  29.         }
  30.         return isFirstLevel;
  31.       }
  32. }
  33. }
复制代码
至于为什么vue在组件注册时没有收集这个参数,还必要从源码那里看,午休时间过了,要继续撸代码了…得空了再分析一下…
处置惩罚方式


给el-submenu添加一个属性 :popper-append-to-body=“true false” 显式的指明appendToBody为false
特别致歉:


此前的处置惩罚方式写错了,写的是:popper-append-to-body=“true” 因此纵然添加了这个属性,也依然是报错的,在此致歉!

到此这篇关于详解Element-ui NavMenu子菜单利用递归生成时利用报错的文章就先容到这了,更多干系Element-ui NavMenu子菜单递归生成内容请搜索草根技能分享从前的文章或继续欣赏下面的干系文章盼望各人以后多多支持草根技能分享!

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作