Vue项目中用递归生成子菜单报错问题怎么办
Admin 2022-10-21 群英技术资讯 499 次浏览
当采用递归方式生成导航栏的子菜单时,菜单可以正常生成,但是当鼠标hover时,会出现循环调用某个(mouseenter)事件,导致最后报错
注:2.13.2 版本,只需对子菜单设置属性 :popper-append-to-body="false" 就不会出现这个问题了
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)
版本:
<!DOCTYPE html> < html > < head > < meta charset = "utf-8" > < title ></ title > <!-- 引入样式 --> < 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 > <!-- 引入组件库 --> < 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: '我的工作台', path: '2', children: [{ title: '选项1', path: '2-1' }, { title: '选项2', path: '2-2', }, ], },{ title:'后台管理', path:'3' }] } }, components: {} }) </ script > </ body > </ html > |
观察递归生成的导航栏代码及报错代码:
?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" ))); //报错代码 } }, |
猜测是因为事件冒泡或下沉导致元素重复派发和接受mouseenter事件,造成了类似死循环的状态,因时间关系,没做深究,后面有时间的时候再查下根本原因(如果记得的话…)
当鼠标移入到菜单中时,触发handleMouseenter方法,但是因为appendToBody为true,所以又派发了鼠标移入事件,然后又回到了这个方法,由此造成了死循环。appendToBody是一个计算属性,那么为什么appendToBody会是true呢?看代码:
?{ name: 'ElSubmenu' , componentName: 'ElSubmenu' , props:{ popperAppendToBody: { type: Boolean, default : undefined } }, computed:{ appendToBody() { return this .popperAppendToBody === undefined ? this .isFirstLevel //未显示指明popperAppendToBody 时,计算这个值 : this .popperAppendToBody; }, isFirstLevel() { let isFirstLevel = true ; let parent = this .$parent; while (parent && parent !== this .rootMenu) { //计算当前是否时第一级菜单。 //看上去是没问题的,因为代码里已经指明了当前的组件名是 componentName: 'ElSubmenu', 但是在调试中发现,componentName的值是Undefined, 因此不管是在哪一级,最后的结果都是 isFirstLevel = true if ([ 'ElSubmenu' , 'ElMenuItemGroup' ].indexOf(parent.$options.componentName) > -1) { isFirstLevel = false ; break ; } else { parent = parent.$parent; } } return isFirstLevel; } } } |
至于为什么vue在组件注册时没有收集这个参数,还需要从源码那边看,午休时间过了,要继续撸代码了…得空了再分析一下…
给el-submenu添加一个属性 :popper-append-to-body=“true false” 显式的指明appendToBody为false
此前的处理方式写错了,写的是:popper-append-to-body=“true” 因此即使添加了这个属性,也依然是报错的,在此致歉!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
本文主要介绍了TypeScript数据类型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
js不会保护hasOwnProperty被非法占用,如果一个对象碰巧存在这个属性, 就需要使用外部的hasOwnProperty 函数来获取正确的结果。当检查对象上某个属性是否存在时,hasOwnProperty 是唯一可用的方法。
这篇文章主要介绍了react-native 实现购物车滑动删除效果的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
这篇文章主要为大家详细介绍了Vue分页组件的封装方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
这篇文章主要给大家分享的是TypeScript 索引签名的理解,索引签名由方括号中的索引名称及其类型组成,后面是冒号和值类型:{ [indexName: KeyType]: ValueType }, KeyType 可以是一个 string、number 或 symbol,而ValueType 可以是任何类型,下面就俩简单了解一下吧
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008