當(dāng)采用遞歸方式生成導(dǎo)航欄的子菜單時(shí),菜單可以正常生成,但是當(dāng)鼠標(biāo)hover時(shí),會(huì)出現(xiàn)循環(huán)調(diào)用某個(gè)(mouseenter)事件,導(dǎo)致最后報(bào)錯(cuò)
處理方式
注:2.13.2 版本,只需對(duì)子菜單設(shè)置屬性 :popper-append-to-body="false" 就不會(huì)出現(xiàn)這個(gè)問(wèn)題了
報(bào)錯(cuò)信息如下:
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)
測(cè)試代碼
版本:
- vue: v2.6.11
- element-ui: 2.13.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
<!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 > <!-- 引入組件庫(kù) --> < 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: '我的工作臺(tái)', path: '2', children: [{ title: '選項(xiàng)1', path: '2-1' }, { title: '選項(xiàng)2', path: '2-2', }, ], },{ title:'后臺(tái)管理', path:'3' }] } }, components: {} }) </ script > </ body > </ html > |
錯(cuò)誤分析
觀察遞歸生成的導(dǎo)航欄代碼及報(bào)錯(cuò)代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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" ))); //報(bào)錯(cuò)代碼 } }, |
猜測(cè)是因?yàn)槭录芭莼蛳鲁翆?dǎo)致元素重復(fù)派發(fā)和接受mouseenter事件,造成了類(lèi)似死循環(huán)的狀態(tài),因時(shí)間關(guān)系,沒(méi)做深究,后面有時(shí)間的時(shí)候再查下根本原因(如果記得的話…)
當(dāng)鼠標(biāo)移入到菜單中時(shí),觸發(fā)handleMouseenter方法,但是因?yàn)閍ppendToBody為true,所以又派發(fā)了鼠標(biāo)移入事件,然后又回到了這個(gè)方法,由此造成了死循環(huán)。appendToBody是一個(gè)計(jì)算屬性,那么為什么appendToBody會(huì)是true呢?看代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
{ name: 'ElSubmenu' , componentName: 'ElSubmenu' , props:{ popperAppendToBody: { type: Boolean, default : undefined } }, computed:{ appendToBody() { return this .popperAppendToBody === undefined ? this .isFirstLevel //未顯示指明popperAppendToBody 時(shí),計(jì)算這個(gè)值 : this .popperAppendToBody; }, isFirstLevel() { let isFirstLevel = true ; let parent = this .$parent; while (parent && parent !== this .rootMenu) { //計(jì)算當(dāng)前是否時(shí)第一級(jí)菜單。 //看上去是沒(méi)問(wèn)題的,因?yàn)榇a里已經(jīng)指明了當(dāng)前的組件名是 componentName: 'ElSubmenu', 但是在調(diào)試中發(fā)現(xiàn),componentName的值是Undefined, 因此不管是在哪一級(jí),最后的結(jié)果都是 isFirstLevel = true if ([ 'ElSubmenu' , 'ElMenuItemGroup' ].indexOf(parent.$options.componentName) > -1) { isFirstLevel = false ; break ; } else { parent = parent.$parent; } } return isFirstLevel; } } } |
至于為什么vue在組件注冊(cè)時(shí)沒(méi)有收集這個(gè)參數(shù),還需要從源碼那邊看,午休時(shí)間過(guò)了,要繼續(xù)擼代碼了…得空了再分析一下…
處理方式
給el-submenu添加一個(gè)屬性 :popper-append-to-body=“true false” 顯式的指明appendToBody為false
特別致歉:
此前的處理方式寫(xiě)錯(cuò)了,寫(xiě)的是:popper-append-to-body=“true” 因此即使添加了這個(gè)屬性,也依然是報(bào)錯(cuò)的,在此致歉!
到此這篇關(guān)于詳解Element-ui NavMenu子菜單使用遞歸生成時(shí)使用報(bào)錯(cuò)的文章就介紹到這了,更多相關(guān)Element-ui NavMenu子菜單遞歸生成內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/qq_34172153/article/details/105177925