1
1
import type { Key } from '../../_util/type' ;
2
- import type { ExtractPropTypes , PropType , UnwrapRef } from 'vue' ;
2
+ import type { ExtractPropTypes , PropType } from 'vue' ;
3
3
import { computed , defineComponent , ref , inject , watchEffect , watch , onMounted , unref } from 'vue' ;
4
4
import shallowEqual from '../../_util/shallowequal' ;
5
5
import type { StoreMenuInfo } from './hooks/useMenuContext' ;
@@ -24,13 +24,15 @@ import MenuItem from './MenuItem';
24
24
import SubMenu from './SubMenu' ;
25
25
import EllipsisOutlined from '@ant-design/icons-vue/EllipsisOutlined' ;
26
26
import { cloneElement } from '../../_util/vnode' ;
27
+ import { OVERFLOW_KEY , PathContext } from './hooks/useKeyPath' ;
27
28
28
29
export const menuProps = {
29
30
id : String ,
30
31
prefixCls : String ,
31
32
disabled : Boolean ,
32
33
inlineCollapsed : Boolean ,
33
34
disabledOverflow : Boolean ,
35
+ forceSubMenuRender : Boolean ,
34
36
openKeys : Array ,
35
37
selectedKeys : Array ,
36
38
activeKey : String , // 内部组件使用
@@ -60,6 +62,7 @@ export type MenuProps = Partial<ExtractPropTypes<typeof menuProps>>;
60
62
const EMPTY_LIST : string [ ] = [ ] ;
61
63
export default defineComponent ( {
62
64
name : 'AMenu' ,
65
+ inheritAttrs : false ,
63
66
props : menuProps ,
64
67
emits : [
65
68
'update:openKeys' ,
@@ -71,7 +74,7 @@ export default defineComponent({
71
74
'update:activeKey' ,
72
75
] ,
73
76
slots : [ 'expandIcon' , 'overflowedIndicator' ] ,
74
- setup ( props , { slots, emit } ) {
77
+ setup ( props , { slots, emit, attrs } ) {
75
78
const { prefixCls, direction } = useConfigInject ( 'menu' , props ) ;
76
79
const store = ref < Record < string , StoreMenuInfo > > ( { } ) ;
77
80
const siderCollapsed = inject ( SiderCollapsedKey , ref ( undefined ) ) ;
@@ -102,7 +105,7 @@ export default defineComponent({
102
105
103
106
const activeKeys = ref ( [ ] ) ;
104
107
const mergedSelectedKeys = ref ( [ ] ) ;
105
- const keyMapStore = ref ( { } ) ;
108
+ const keyMapStore = ref < Record < Key , StoreMenuInfo > > ( { } ) ;
106
109
watch (
107
110
store ,
108
111
( ) => {
@@ -117,11 +120,9 @@ export default defineComponent({
117
120
watchEffect ( ( ) => {
118
121
if ( props . activeKey !== undefined ) {
119
122
let keys = [ ] ;
120
- const menuInfo = props . activeKey
121
- ? ( keyMapStore . value [ props . activeKey ] as UnwrapRef < StoreMenuInfo > )
122
- : undefined ;
123
+ const menuInfo = props . activeKey ? keyMapStore . value [ props . activeKey ] : undefined ;
123
124
if ( menuInfo && props . activeKey !== undefined ) {
124
- keys = [ ... menuInfo . parentKeys , props . activeKey ] ;
125
+ keys = uniq ( [ ] . concat ( unref ( menuInfo . parentKeys ) , props . activeKey ) ) ;
125
126
} else {
126
127
keys = [ ] ;
127
128
}
@@ -139,22 +140,21 @@ export default defineComponent({
139
140
{ immediate : true } ,
140
141
) ;
141
142
142
- const selectedSubMenuEventKeys = ref ( [ ] ) ;
143
-
143
+ const selectedSubMenuKeys = ref ( [ ] ) ;
144
144
watch (
145
145
[ keyMapStore , mergedSelectedKeys ] ,
146
146
( ) => {
147
- let subMenuParentEventKeys = [ ] ;
147
+ let subMenuParentKeys = [ ] ;
148
148
mergedSelectedKeys . value . forEach ( key => {
149
149
const menuInfo = keyMapStore . value [ key ] ;
150
150
if ( menuInfo ) {
151
- subMenuParentEventKeys . push ( ... unref ( menuInfo . parentEventKeys ) ) ;
151
+ subMenuParentKeys = subMenuParentKeys . concat ( unref ( menuInfo . parentKeys ) ) ;
152
152
}
153
153
} ) ;
154
154
155
- subMenuParentEventKeys = uniq ( subMenuParentEventKeys ) ;
156
- if ( ! shallowEqual ( selectedSubMenuEventKeys . value , subMenuParentEventKeys ) ) {
157
- selectedSubMenuEventKeys . value = subMenuParentEventKeys ;
155
+ subMenuParentKeys = uniq ( subMenuParentKeys ) ;
156
+ if ( ! shallowEqual ( selectedSubMenuKeys . value , subMenuParentKeys ) ) {
157
+ selectedSubMenuKeys . value = subMenuParentKeys ;
158
158
}
159
159
} ,
160
160
{ immediate : true } ,
@@ -321,16 +321,16 @@ export default defineComponent({
321
321
triggerSelection ( info ) ;
322
322
} ;
323
323
324
- const onInternalOpenChange = ( eventKey : Key , open : boolean ) => {
325
- const { key , childrenEventKeys } = store . value [ eventKey ] ;
324
+ const onInternalOpenChange = ( key : Key , open : boolean ) => {
325
+ const childrenEventKeys = keyMapStore . value [ key ] . childrenEventKeys ;
326
326
let newOpenKeys = mergedOpenKeys . value . filter ( k => k !== key ) ;
327
327
328
328
if ( open ) {
329
329
newOpenKeys . push ( key ) ;
330
330
} else if ( mergedMode . value !== 'inline' ) {
331
331
// We need find all related popup to close
332
332
const subPathKeys = getChildrenKeys ( childrenEventKeys ) ;
333
- newOpenKeys = newOpenKeys . filter ( k => ! subPathKeys . includes ( k ) ) ;
333
+ newOpenKeys = uniq ( newOpenKeys . filter ( k => ! subPathKeys . includes ( k ) ) ) ;
334
334
}
335
335
336
336
if ( ! shallowEqual ( mergedOpenKeys , newOpenKeys ) ) {
@@ -388,9 +388,10 @@ export default defineComponent({
388
388
onItemClick : onInternalClick ,
389
389
registerMenuInfo,
390
390
unRegisterMenuInfo,
391
- selectedSubMenuEventKeys ,
391
+ selectedSubMenuKeys ,
392
392
isRootMenu : ref ( true ) ,
393
393
expandIcon,
394
+ forceSubMenuRender : computed ( ( ) => props . forceSubMenuRender ) ,
394
395
} ) ;
395
396
return ( ) => {
396
397
const childList = flattenChildren ( slots . default ?.( ) ) ;
@@ -415,43 +416,63 @@ export default defineComponent({
415
416
const overflowedIndicator = slots . overflowedIndicator ?.( ) || < EllipsisOutlined /> ;
416
417
417
418
return (
418
- < Overflow
419
- prefixCls = { `${ prefixCls . value } -overflow` }
420
- component = "ul"
421
- itemComponent = { MenuItem }
422
- class = { className . value }
423
- role = "menu"
424
- id = { props . id }
425
- data = { wrappedChildList }
426
- renderRawItem = { node => node }
427
- renderRawRest = { omitItems => {
428
- // We use origin list since wrapped list use context to prevent open
429
- const len = omitItems . length ;
430
-
431
- const originOmitItems = len ? childList . slice ( - len ) : null ;
432
-
433
- return (
434
- < SubMenu
435
- eventKey = { Overflow . OVERFLOW_KEY }
436
- title = { overflowedIndicator }
437
- disabled = { allVisible }
438
- internalPopupClose = { len === 0 }
439
- >
440
- { originOmitItems }
441
- </ SubMenu >
442
- ) ;
443
- } }
444
- maxCount = {
445
- mergedMode . value !== 'horizontal' || props . disabledOverflow
446
- ? Overflow . INVALIDATE
447
- : Overflow . RESPONSIVE
448
- }
449
- ssr = "full"
450
- data-menu-list
451
- onVisibleChange = { newLastIndex => {
452
- lastVisibleIndex . value = newLastIndex ;
453
- } }
454
- />
419
+ < >
420
+ < Overflow
421
+ { ...attrs }
422
+ prefixCls = { `${ prefixCls . value } -overflow` }
423
+ component = "ul"
424
+ itemComponent = { MenuItem }
425
+ class = { className . value }
426
+ role = "menu"
427
+ id = { props . id }
428
+ data = { wrappedChildList }
429
+ renderRawItem = { node => node }
430
+ renderRawRest = { omitItems => {
431
+ // We use origin list since wrapped list use context to prevent open
432
+ const len = omitItems . length ;
433
+
434
+ const originOmitItems = len ? childList . slice ( - len ) : null ;
435
+
436
+ return (
437
+ < >
438
+ < SubMenu
439
+ eventKey = { OVERFLOW_KEY }
440
+ key = { OVERFLOW_KEY }
441
+ title = { overflowedIndicator }
442
+ disabled = { allVisible }
443
+ internalPopupClose = { len === 0 }
444
+ >
445
+ { originOmitItems }
446
+ </ SubMenu >
447
+ < PathContext >
448
+ < SubMenu
449
+ eventKey = { OVERFLOW_KEY }
450
+ key = { OVERFLOW_KEY }
451
+ title = { overflowedIndicator }
452
+ disabled = { allVisible }
453
+ internalPopupClose = { len === 0 }
454
+ >
455
+ { originOmitItems }
456
+ </ SubMenu >
457
+ </ PathContext >
458
+ </ >
459
+ ) ;
460
+ } }
461
+ maxCount = {
462
+ mergedMode . value !== 'horizontal' || props . disabledOverflow
463
+ ? Overflow . INVALIDATE
464
+ : Overflow . RESPONSIVE
465
+ }
466
+ ssr = "full"
467
+ data-menu-list
468
+ onVisibleChange = { newLastIndex => {
469
+ lastVisibleIndex . value = newLastIndex ;
470
+ } }
471
+ />
472
+ < div style = { { display : 'none' } } aria-hidden >
473
+ < PathContext > { wrappedChildList } </ PathContext >
474
+ </ div >
475
+ </ >
455
476
) ;
456
477
} ;
457
478
} ,
0 commit comments