vxe-pc-ui 4.16.9 → 4.16.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/all.esm.js +284 -147
  2. package/dist/style.css +1 -1
  3. package/dist/style.min.css +1 -1
  4. package/es/checkbox/style.css +1 -0
  5. package/es/checkbox/style.min.css +1 -1
  6. package/es/icon/{iconfont.1783939831164.ttf → iconfont.1784122303243.ttf} +0 -0
  7. package/es/icon/iconfont.1784122303243.woff +0 -0
  8. package/es/icon/iconfont.1784122303243.woff2 +0 -0
  9. package/es/icon/style.css +33 -2
  10. package/es/icon/style.min.css +1 -1
  11. package/{lib/icon/style/iconfont.1783939831164.ttf → es/iconfont.1784122303243.ttf} +0 -0
  12. package/es/iconfont.1784122303243.woff +0 -0
  13. package/es/iconfont.1784122303243.woff2 +0 -0
  14. package/es/language/en-US.js +3 -3
  15. package/es/language/hy-AM.js +3 -3
  16. package/es/language/zh-CN.js +3 -3
  17. package/es/layout-aside/src/layout-aside.js +13 -20
  18. package/es/layout-aside/style.css +1 -3
  19. package/es/layout-aside/style.min.css +1 -1
  20. package/es/menu/src/menu.js +265 -121
  21. package/es/menu/style.css +51 -3
  22. package/es/menu/style.min.css +1 -1
  23. package/es/modal/src/modal.js +2 -2
  24. package/es/radio/style.css +1 -0
  25. package/es/radio/style.min.css +1 -1
  26. package/es/style.css +1 -1
  27. package/es/style.min.css +1 -1
  28. package/es/tree-select/src/tree-select.js +1 -1
  29. package/es/ui/index.js +1 -1
  30. package/es/ui/src/log.js +1 -1
  31. package/es/vxe-checkbox/style.css +1 -0
  32. package/es/vxe-checkbox/style.min.css +1 -1
  33. package/es/vxe-icon/style.css +33 -2
  34. package/es/vxe-icon/style.min.css +1 -1
  35. package/es/vxe-layout-aside/style.css +1 -3
  36. package/es/vxe-layout-aside/style.min.css +1 -1
  37. package/es/vxe-menu/style.css +51 -3
  38. package/es/vxe-menu/style.min.css +1 -1
  39. package/es/vxe-radio/style.css +1 -0
  40. package/es/vxe-radio/style.min.css +1 -1
  41. package/lib/checkbox/style/style.css +1 -0
  42. package/lib/checkbox/style/style.min.css +1 -1
  43. package/lib/{iconfont.1783939831164.ttf → icon/style/iconfont.1784122303243.ttf} +0 -0
  44. package/lib/icon/style/iconfont.1784122303243.woff +0 -0
  45. package/lib/icon/style/iconfont.1784122303243.woff2 +0 -0
  46. package/lib/icon/style/style.css +33 -2
  47. package/lib/icon/style/style.min.css +33 -2
  48. package/{es/iconfont.1783939831164.ttf → lib/iconfont.1784122303243.ttf} +0 -0
  49. package/lib/iconfont.1784122303243.woff +0 -0
  50. package/lib/iconfont.1784122303243.woff2 +0 -0
  51. package/lib/index.umd.js +302 -136
  52. package/lib/index.umd.min.js +1 -1
  53. package/lib/language/en-US.js +3 -3
  54. package/lib/language/en-US.min.js +1 -1
  55. package/lib/language/en-US.umd.js +3 -3
  56. package/lib/language/hy-AM.js +3 -3
  57. package/lib/language/hy-AM.min.js +1 -1
  58. package/lib/language/hy-AM.umd.js +3 -3
  59. package/lib/language/zh-CN.js +3 -3
  60. package/lib/language/zh-CN.min.js +1 -1
  61. package/lib/language/zh-CN.umd.js +3 -3
  62. package/lib/layout-aside/src/layout-aside.js +12 -18
  63. package/lib/layout-aside/src/layout-aside.min.js +1 -1
  64. package/lib/layout-aside/style/style.css +1 -3
  65. package/lib/layout-aside/style/style.min.css +1 -1
  66. package/lib/menu/src/menu.js +283 -116
  67. package/lib/menu/src/menu.min.js +1 -1
  68. package/lib/menu/style/style.css +51 -3
  69. package/lib/menu/style/style.min.css +1 -1
  70. package/lib/modal/src/modal.js +2 -2
  71. package/lib/modal/src/modal.min.js +1 -1
  72. package/lib/radio/style/style.css +1 -0
  73. package/lib/radio/style/style.min.css +1 -1
  74. package/lib/style.css +1 -1
  75. package/lib/style.min.css +1 -1
  76. package/lib/tree-select/src/tree-select.js +1 -1
  77. package/lib/tree-select/src/tree-select.min.js +1 -1
  78. package/lib/ui/index.js +1 -1
  79. package/lib/ui/index.min.js +1 -1
  80. package/lib/ui/src/log.js +1 -1
  81. package/lib/ui/src/log.min.js +1 -1
  82. package/lib/vxe-checkbox/style/style.css +1 -0
  83. package/lib/vxe-checkbox/style/style.min.css +1 -1
  84. package/lib/vxe-icon/style/style.css +33 -2
  85. package/lib/vxe-icon/style/style.min.css +1 -1
  86. package/lib/vxe-layout-aside/style/style.css +1 -3
  87. package/lib/vxe-layout-aside/style/style.min.css +1 -1
  88. package/lib/vxe-menu/style/style.css +51 -3
  89. package/lib/vxe-menu/style/style.min.css +1 -1
  90. package/lib/vxe-radio/style/style.css +1 -0
  91. package/lib/vxe-radio/style/style.min.css +1 -1
  92. package/package.json +2 -2
  93. package/packages/language/en-US.ts +3 -3
  94. package/packages/language/hy-AM.ts +3 -3
  95. package/packages/language/zh-CN.ts +3 -3
  96. package/packages/layout-aside/src/layout-aside.ts +15 -21
  97. package/packages/menu/src/menu.ts +302 -132
  98. package/packages/modal/src/modal.ts +3 -3
  99. package/packages/tree-select/src/tree-select.ts +1 -1
  100. package/styles/components/checkbox.scss +1 -0
  101. package/styles/components/icon.scss +33 -4
  102. package/styles/components/layout-aside.scss +1 -3
  103. package/styles/components/menu.scss +64 -1
  104. package/styles/components/radio.scss +1 -0
  105. package/styles/icon/iconfont.ttf +0 -0
  106. package/styles/icon/iconfont.woff +0 -0
  107. package/styles/icon/iconfont.woff2 +0 -0
  108. package/styles/theme/base.scss +1 -1
  109. package/styles/theme/dark.scss +1 -0
  110. package/styles/theme/light.scss +1 -0
  111. package/styles/variable.scss +2 -1
  112. package/types/components/icon.d.ts +1 -1
  113. package/types/components/layout-aside.d.ts +5 -4
  114. package/types/components/menu.d.ts +65 -17
  115. package/types/components/modal.d.ts +2 -2
  116. package/types/components/table.d.ts +11 -11
  117. package/types/components/toolbar.d.ts +1 -1
  118. package/es/icon/iconfont.1783939831164.woff +0 -0
  119. package/es/icon/iconfont.1783939831164.woff2 +0 -0
  120. package/es/iconfont.1783939831164.woff +0 -0
  121. package/es/iconfont.1783939831164.woff2 +0 -0
  122. package/lib/icon/style/iconfont.1783939831164.woff +0 -0
  123. package/lib/icon/style/iconfont.1783939831164.woff2 +0 -0
  124. package/lib/iconfont.1783939831164.woff +0 -0
  125. package/lib/iconfont.1783939831164.woff2 +0 -0
@@ -1,14 +1,14 @@
1
- import { ref, h, reactive, PropType, inject, resolveComponent, watch, VNode, computed, nextTick, onBeforeUnmount, onMounted } from 'vue'
1
+ import { ref, h, reactive, Teleport, PropType, inject, resolveComponent, watch, VNode, computed, nextTick, onBeforeUnmount, onMounted } from 'vue'
2
2
  import { defineVxeComponent } from '../../ui/src/comp'
3
3
  import XEUtils from 'xe-utils'
4
4
  import { VxeUI, createEvent, permission, useSize, globalEvents, renderEmptyElement } from '../../ui'
5
- import { toCssUnit } from '../../ui/src/dom'
5
+ import { scrollToView, toCssUnit } from '../../ui/src/dom'
6
6
  import { getLastZIndex, nextZIndex, isEnableConf } from '../../ui/src/utils'
7
7
  import { getSlotVNs } from '../../ui/src/vn'
8
8
  import { createComponentLog } from '../../ui/src/log'
9
9
  import VxeLoadingComponent from '../../loading'
10
10
 
11
- import type { VxeMenuDefines, VxeMenuPropTypes, MenuInternalData, MenuReactData, VxeMenuEmits, MenuMethods, VxeComponentSlotType, VxeLayoutAsidePropTypes, MenuPrivateMethods, MenuPrivateRef, VxeMenuPrivateComputed, VxeMenuConstructor, VxeMenuPrivateMethods, ValueOf, VxeLayoutAsideConstructor, VxeLayoutAsidePrivateMethods } from '../../../types'
11
+ import type { VxeMenuDefines, VxeMenuPropTypes, MenuInternalData, MenuReactData, VxeMenuEmits, MenuMethods, VxeComponentSlotType, MenuPrivateMethods, MenuPrivateRef, VxeMenuPrivateComputed, VxeMenuConstructor, VxeMenuPrivateMethods, ValueOf, VxeLayoutAsideConstructor, VxeLayoutAsidePrivateMethods } from '../../../types'
12
12
 
13
13
  const { errLog } = createComponentLog('menu')
14
14
 
@@ -16,6 +16,10 @@ const { menus, getConfig, getIcon } = VxeUI
16
16
 
17
17
  function createInternalData (): MenuInternalData {
18
18
  return {
19
+ lastActiveTime: 0,
20
+ menuInitMaps: {},
21
+ menuCacheMaps: {},
22
+ menuKeyMaps: {},
19
23
  menuEffectMaps: {}
20
24
  }
21
25
  }
@@ -39,10 +43,19 @@ export default defineVxeComponent({
39
43
  props: {
40
44
  modelValue: [String, Number] as PropType<VxeMenuPropTypes.ModelValue>,
41
45
  expandAll: Boolean as PropType<VxeMenuPropTypes.ExpandAll>,
46
+ expandKeys: Array as PropType<VxeMenuPropTypes.ExpandKeys>,
42
47
  accordion: {
43
48
  type: Boolean as PropType<VxeMenuPropTypes.Accordion>,
44
49
  default: () => getConfig().menu.accordion
45
50
  },
51
+ border: {
52
+ type: [Boolean, String] as PropType<VxeMenuPropTypes.Border>,
53
+ default: () => getConfig().menu.border
54
+ },
55
+ optionProps: {
56
+ type: Object as PropType<VxeMenuPropTypes.OptionProps>,
57
+ default: () => getConfig().menu.optionProps
58
+ },
46
59
  collapsed: {
47
60
  type: Boolean as PropType<VxeMenuPropTypes.Collapsed>,
48
61
  default: null
@@ -88,6 +101,43 @@ export default defineVxeComponent({
88
101
  return Object.assign({}, getConfig().menu.menuConfig, props.menuConfig)
89
102
  })
90
103
 
104
+ const computePropsOpts = computed(() => {
105
+ return Object.assign({}, getConfig().menu.optionProps, props.optionProps)
106
+ })
107
+
108
+ const computeTitleField = computed(() => {
109
+ const propsOpts = computePropsOpts.value
110
+ return propsOpts.title || 'title'
111
+ })
112
+
113
+ const computeKeyField = computed(() => {
114
+ const propsOpts = computePropsOpts.value
115
+ return propsOpts.name || 'name'
116
+ })
117
+
118
+ const computeChildrenField = computed(() => {
119
+ const propsOpts = computePropsOpts.value
120
+ return propsOpts.children || 'children'
121
+ })
122
+
123
+ const computeLinkUrlField = computed(() => {
124
+ const propsOpts = computePropsOpts.value
125
+ return propsOpts.linkUrl || 'href'
126
+ })
127
+
128
+ const computeRouterLinkField = computed(() => {
129
+ const propsOpts = computePropsOpts.value
130
+ return propsOpts.routerLink || 'routerLink'
131
+ })
132
+
133
+ const computeCurrBorder = computed(() => {
134
+ const { border } = props
135
+ if (border) {
136
+ return border === true ? 'first-group' : border
137
+ }
138
+ return ''
139
+ })
140
+
91
141
  const computeIsCollapsed = computed(() => {
92
142
  const { collapsed } = props
93
143
  if (XEUtils.isBoolean(collapsed)) {
@@ -99,20 +149,13 @@ export default defineVxeComponent({
99
149
  return false
100
150
  })
101
151
 
102
- const computeCollapseWidth = computed(() => {
103
- let collapseWidth: VxeLayoutAsidePropTypes.CollapseWidth = ''
104
- if ($xeLayoutAside) {
105
- collapseWidth = $xeLayoutAside.props.collapseWidth || ''
106
- }
107
- return collapseWidth
108
- })
109
-
110
- const computeCollapseEnterWidth = computed(() => {
111
- let width: VxeLayoutAsidePropTypes.Width = ''
152
+ const computeVarStyle = computed(() => {
112
153
  if ($xeLayoutAside) {
113
- width = $xeLayoutAside.props.width || ''
154
+ const { computeVarStyle: asideComputeVarStyle } = $xeLayoutAside.getComputeMaps()
155
+ const asideVarStyle = asideComputeVarStyle.value
156
+ return asideVarStyle
114
157
  }
115
- return width
158
+ return {}
116
159
  })
117
160
 
118
161
  const computeMaps: VxeMenuPrivateComputed = {
@@ -124,6 +167,7 @@ export default defineVxeComponent({
124
167
  props,
125
168
  context,
126
169
  reactData,
170
+ internalData,
127
171
 
128
172
  getRefMaps: () => refMaps,
129
173
  getComputeMaps: () => computeMaps
@@ -141,12 +185,14 @@ export default defineVxeComponent({
141
185
 
142
186
  const updateActiveMenu = (isDefExpand?: boolean) => {
143
187
  const { activeName } = reactData
144
- XEUtils.eachTree(reactData.menuList, (item, index, items, path, parent, nodes) => {
188
+ const { menuInitMaps } = internalData
189
+ XEUtils.eachTree(reactData.menuList, (item, index, items, path, parentItem, nodes) => {
145
190
  if (item.itemKey === activeName) {
146
191
  nodes.forEach(obj => {
147
192
  obj.isActive = true
148
193
  if (isDefExpand) {
149
194
  obj.isExpand = true
195
+ menuInitMaps[obj.itemId] = true
150
196
  }
151
197
  })
152
198
  item.isExactActive = true
@@ -158,31 +204,68 @@ export default defineVxeComponent({
158
204
  }
159
205
 
160
206
  const updateMenuConfig = () => {
161
- const { options, expandAll } = props
162
- reactData.menuList = XEUtils.mapTree(options, (item, index, items, path, parent) => {
163
- const objItem = {
164
- ...item,
165
- parentKey: parent ? (parent.name || path.slice(0, path.length - 1).join(',')) : '',
207
+ const { options, expandAll, expandKeys } = props
208
+ const muInitMaps: Record<string, boolean> = {}
209
+ const titleField = computeTitleField.value
210
+ const keyField = computeKeyField.value
211
+ const childrenField = computeChildrenField.value
212
+ const linkUrlField = computeLinkUrlField.value
213
+ const routerLinkField = computeRouterLinkField.value
214
+ const defaultExpandMaps: Record<string, boolean> = {}
215
+ if (expandKeys) {
216
+ expandKeys.forEach(key => {
217
+ defaultExpandMaps[key] = true
218
+ })
219
+ }
220
+ const muCacheMaps: Record<string, VxeMenuDefines.MenuItem> = {}
221
+ const muKeyMaps: Record<string, VxeMenuDefines.MenuItem> = {}
222
+ reactData.menuList = XEUtils.mapTree(options, (item, index, items, path, parentItem) => {
223
+ const itemId = ++nemuUniqueKey
224
+ const itemKey = item[keyField] || path.join(',')
225
+ const childList = item[childrenField]
226
+ const hasChild = childList && childList.length > 0
227
+ const isExpand = hasChild ? (XEUtils.isBoolean(item.expanded) ? item.expanded : (defaultExpandMaps[itemKey] || !!expandAll)) : false
228
+ if (isExpand) {
229
+ muInitMaps[itemId] = true
230
+ }
231
+ const objItem: VxeMenuDefines.MenuItem = {
232
+ itemConf: item,
233
+ title: item[titleField],
234
+ name: item[keyField],
235
+ icon: item.icon,
236
+ linkUrl: item[linkUrlField],
237
+ linkTarget: item.linkTarget,
238
+ routerLink: item[routerLinkField],
239
+ permissionCode: item.permissionCode,
240
+ children: childList,
241
+ slots: item.slots,
242
+ parentKey: parentItem ? (parentItem.name || path.slice(0, path.length - 1).join(',')) : '',
166
243
  level: path.length,
167
- itemId: ++nemuUniqueKey,
168
- itemKey: item.name || path.join(','),
244
+ itemId,
245
+ itemKey,
169
246
  isExactActive: false,
170
247
  isActive: false,
171
- isExpand: XEUtils.isBoolean(item.expanded) ? item.expanded : !!expandAll,
172
- hasChild: item.children && item.children.length > 0
173
- } as VxeMenuDefines.MenuItem
248
+ isExpand,
249
+ hasChild,
250
+ childList: []
251
+ }
252
+ if (muKeyMaps[itemKey]) {
253
+ errLog('vxe.error.repeatKey', [keyField, item[keyField]])
254
+ }
255
+ muCacheMaps[itemId] = objItem
256
+ muKeyMaps[itemKey] = objItem
174
257
  return objItem
175
258
  }, { children: 'children', mapChildren: 'childList' })
259
+ internalData.menuInitMaps = muInitMaps
260
+ internalData.menuCacheMaps = muCacheMaps
261
+ internalData.menuKeyMaps = muKeyMaps
176
262
  }
177
263
 
178
264
  const updateCollapseStyle = () => {
179
265
  const { collapseFixed } = props
180
266
  if (collapseFixed) {
181
267
  nextTick(() => {
182
- const { isEnterCollapse } = reactData
183
268
  const isCollapsed = computeIsCollapsed.value
184
- const collapseEnterWidth = computeCollapseEnterWidth.value
185
- const collapseWidth = computeCollapseWidth.value
186
269
  const el = refElem.value
187
270
  if (el) {
188
271
  const clientRect = el.getBoundingClientRect()
@@ -192,7 +275,6 @@ export default defineVxeComponent({
192
275
  top: toCssUnit(clientRect.top),
193
276
  left: toCssUnit(clientRect.left),
194
277
  height: toCssUnit(parentNode.clientHeight),
195
- width: isEnterCollapse ? (collapseEnterWidth ? toCssUnit(collapseEnterWidth) : '') : (collapseWidth ? toCssUnit(collapseWidth) : ''),
196
278
  zIndex: reactData.collapseZindex
197
279
  }
198
280
  : {}
@@ -209,12 +291,6 @@ export default defineVxeComponent({
209
291
  if (isCollapsed) {
210
292
  if (!initialized) {
211
293
  reactData.initialized = true
212
- nextTick(() => {
213
- const collapseEl = refCollapseElem.value
214
- if (collapseEl) {
215
- document.body.appendChild(collapseEl)
216
- }
217
- })
218
294
  }
219
295
  }
220
296
  reactData.isEnterCollapse = false
@@ -225,7 +301,7 @@ export default defineVxeComponent({
225
301
 
226
302
  const handleClickIconCollapse = (evnt: MouseEvent, item: VxeMenuDefines.MenuItem, itemList: VxeMenuDefines.MenuItem[]) => {
227
303
  const { accordion } = props
228
- const { menuEffectMaps } = internalData
304
+ const { menuEffectMaps, menuInitMaps } = internalData
229
305
  const { itemId, hasChild, isExpand } = item
230
306
  const isCollapsed = computeIsCollapsed.value
231
307
  const expanded = !isExpand
@@ -245,6 +321,7 @@ export default defineVxeComponent({
245
321
  })
246
322
  }
247
323
  item.isExpand = expanded
324
+ menuInitMaps[itemId] = true
248
325
 
249
326
  const wrapperEl = isCollapsed ? refCollapseElem.value : refElem.value
250
327
  if (wrapperEl) {
@@ -284,7 +361,7 @@ export default defineVxeComponent({
284
361
  const menuOpts = computeMenuOpts.value
285
362
  if (menuConfig ? isEnableConf(menuOpts) : menuOpts.enabled) {
286
363
  const { options, visibleMethod } = menuOpts
287
- if (!visibleMethod || visibleMethod({ $menu: $xeMenu, options, currentMenu: item })) {
364
+ if (!visibleMethod || visibleMethod({ $menu: $xeMenu, options, currentMenu: item, currentOption: item.itemConf })) {
288
365
  if (VxeUI.contextMenu) {
289
366
  VxeUI.contextMenu.openByEvent(evnt, {
290
367
  options,
@@ -293,7 +370,7 @@ export default defineVxeComponent({
293
370
  const { option } = eventParams
294
371
  const gMenuOpts = menus.get(option.code)
295
372
  const mmMethod = gMenuOpts ? gMenuOpts.menuMenuMethod : null
296
- const params = { menu: option, currentMenu: item, $event: evnt, $menu: $xeMenu }
373
+ const params = { menu: option, currentMenu: item, currentOption: item.itemConf, $event: evnt, $menu: $xeMenu }
297
374
  if (mmMethod) {
298
375
  mmMethod(params, evnt)
299
376
  }
@@ -308,20 +385,24 @@ export default defineVxeComponent({
308
385
  }
309
386
 
310
387
  const handleClickMenu = (evnt: MouseEvent, item: VxeMenuDefines.MenuItem, itemList: VxeMenuDefines.MenuItem[]) => {
311
- const { itemKey, routerLink, hasChild } = item
312
- if (routerLink) {
388
+ const { itemKey, linkUrl, routerLink, hasChild } = item
389
+ if (linkUrl || routerLink) {
313
390
  emitModel(itemKey)
314
- handleMenuMouseleave()
391
+ reactData.isEnterCollapse = false
392
+ internalData.lastActiveTime = Date.now()
315
393
  } else {
316
394
  if (hasChild) {
317
395
  handleClickIconCollapse(evnt, item, itemList)
318
396
  } else {
319
397
  emitModel(itemKey)
320
- handleMenuMouseleave()
398
+ reactData.isEnterCollapse = false
399
+ internalData.lastActiveTime = Date.now()
321
400
  }
322
401
  }
323
402
  const params = {
324
403
  currentMenu: item,
404
+ currentOption: item.itemConf,
405
+ option: item.itemConf,
325
406
 
326
407
  // 已废弃
327
408
  menu: item
@@ -330,27 +411,14 @@ export default defineVxeComponent({
330
411
  }
331
412
 
332
413
  const handleMenuMouseenter = () => {
333
- const { collapseStyle } = reactData
334
- const collapseEnterWidth = computeCollapseEnterWidth.value
335
- reactData.collapseStyle = Object.assign({}, collapseStyle, {
336
- width: collapseEnterWidth ? toCssUnit(collapseEnterWidth) : ''
337
- })
338
- reactData.isEnterCollapse = true
339
- }
414
+ const { lastActiveTime } = internalData
340
415
 
341
- const handleMenuMouseover = () => {
342
- const { isEnterCollapse } = reactData
343
- if (!isEnterCollapse) {
344
- handleMenuMouseenter()
416
+ if (lastActiveTime < Date.now() - 500) {
417
+ reactData.isEnterCollapse = true
345
418
  }
346
419
  }
347
420
 
348
421
  const handleMenuMouseleave = () => {
349
- const { collapseStyle } = reactData
350
- const el = refElem.value
351
- reactData.collapseStyle = Object.assign({}, collapseStyle, {
352
- width: el ? toCssUnit(el.offsetWidth) : ''
353
- })
354
422
  reactData.isEnterCollapse = false
355
423
  }
356
424
 
@@ -370,8 +438,70 @@ export default defineVxeComponent({
370
438
  emit(type, createEvent(evnt, { $menu: $xeMenu }, params))
371
439
  }
372
440
 
441
+ const handleScrollToView = (itemId: number) => {
442
+ const wrapperEl = refElem.value
443
+ const nemuEl = wrapperEl ? wrapperEl.querySelector<HTMLDivElement>(`.vxe-menu--item-wrapper[data-menu-id="${itemId}"]`) : null
444
+ if (nemuEl) {
445
+ scrollToView(nemuEl)
446
+ return true
447
+ }
448
+ return false
449
+ }
450
+
373
451
  const menuMethods: MenuMethods = {
374
- dispatchEvent
452
+ dispatchEvent,
453
+ setExpandByMenuKey (menuKeys, expanded) {
454
+ const { menuKeyMaps, menuInitMaps } = internalData
455
+ if (menuKeys) {
456
+ if (!XEUtils.isArray(menuKeys)) {
457
+ menuKeys = [menuKeys]
458
+ }
459
+ menuKeys.forEach(mKey => {
460
+ const menuItem = menuKeyMaps[mKey]
461
+ if (menuItem) {
462
+ if (expanded) {
463
+ menuInitMaps[menuItem.itemId] = true
464
+ }
465
+ menuItem.isExpand = !!expanded
466
+ }
467
+ })
468
+ }
469
+ return nextTick()
470
+ },
471
+ clearAllExpandMenu () {
472
+ const { menuList } = reactData
473
+ XEUtils.eachTree(menuList, (item) => {
474
+ item.isExpand = false
475
+ }, { children: 'childList' })
476
+ internalData.menuInitMaps = {}
477
+ return nextTick()
478
+ },
479
+ scrollToMenuKey (menuKey) {
480
+ const { menuKeyMaps } = internalData
481
+ const menuItem = menuKeyMaps[menuKey]
482
+ if (!menuItem) {
483
+ return nextTick()
484
+ }
485
+ const { itemId } = menuItem
486
+ if (handleScrollToView(itemId)) {
487
+ return nextTick()
488
+ }
489
+ return nextTick().then(() => {
490
+ handleScrollToView(itemId)
491
+ })
492
+ },
493
+ scrollToActiveMenu () {
494
+ const { activeName } = reactData
495
+ if (activeName) {
496
+ return $xeMenu.scrollToMenuKey(activeName)
497
+ }
498
+ return nextTick().then(() => {
499
+ const { activeName } = reactData
500
+ if (activeName) {
501
+ return $xeMenu.scrollToMenuKey(activeName)
502
+ }
503
+ })
504
+ }
375
505
  }
376
506
 
377
507
  const menuPrivateMethods: MenuPrivateMethods = {
@@ -388,11 +518,10 @@ export default defineVxeComponent({
388
518
  const title = getMenuTitle(item)
389
519
  const isCollapsed = computeIsCollapsed.value
390
520
  const params = {
391
- currentMenu: item as Required<VxeMenuDefines.MenuItem>,
392
- collapsed: isCollapsed,
393
-
394
- // 已废弃
395
- option: item as Required<VxeMenuPropTypes.MenuOption>
521
+ currentMenu: item,
522
+ currentOption: item.itemConf,
523
+ option: item.itemConf,
524
+ collapsed: isCollapsed
396
525
  }
397
526
  return [
398
527
  optionSlot
@@ -430,90 +559,110 @@ export default defineVxeComponent({
430
559
  }
431
560
 
432
561
  const renderDefaultChildren = (item: VxeMenuDefines.MenuItem, itemList: VxeMenuDefines.MenuItem[]): VNode => {
433
- const { itemId, itemKey, level, hasChild, isActive, isExactActive, isExpand, routerLink, childList } = item
562
+ const { itemId, itemKey, level, hasChild, isActive, isExactActive, isExpand, linkUrl, routerLink, linkTarget, childList } = item
434
563
  const { isEnterCollapse } = reactData
564
+ const { menuInitMaps } = internalData
435
565
  const isCollapsed = computeIsCollapsed.value
436
566
  if (item.permissionCode) {
437
567
  if (!permission.checkVisible(item.permissionCode)) {
438
568
  return renderEmptyElement($xeMenu)
439
569
  }
440
570
  }
571
+ const isExpandChild = (!isCollapsed || isEnterCollapse) && isExpand
572
+ const linkOns = {
573
+ onContextmenu (evnt: MouseEvent) {
574
+ handleContextmenuEvent(evnt, item)
575
+ },
576
+ onClick (evnt: MouseEvent) {
577
+ handleClickMenu(evnt, item, itemList)
578
+ }
579
+ }
441
580
  return h('div', {
442
581
  key: itemKey,
443
582
  class: ['vxe-menu--item-wrapper', `vxe-menu--item-level${level}`, {
583
+ 'has--child': hasChild,
444
584
  'is--exact-active': isExactActive,
445
585
  'is--active': isActive,
446
- 'is--expand': (!isCollapsed || isEnterCollapse) && isExpand
586
+ 'is--expand': isExpandChild
447
587
  }],
448
588
  'data-menu-id': itemId
449
589
  }, [
450
- routerLink
451
- ? h(resolveComponent('router-link'), {
452
- class: 'vxe-menu--item-link',
453
- to: routerLink,
454
- onContextmenu (evnt: MouseEvent) {
455
- handleContextmenuEvent(evnt, item)
456
- },
457
- onClick (evnt: MouseEvent) {
458
- handleClickMenu(evnt, item, itemList)
459
- }
460
- }, {
461
- default: () => renderMenuTitle(item, itemList)
462
- })
463
- : h('div', {
464
- class: 'vxe-menu--item-link',
465
- onContextmenu (evnt: MouseEvent) {
466
- handleContextmenuEvent(evnt, item)
467
- },
468
- onClick (evnt: MouseEvent) {
469
- handleClickMenu(evnt, item, itemList)
470
- }
471
- }, renderMenuTitle(item, itemList)),
590
+ linkUrl
591
+ ? h('a', {
592
+ class: 'vxe-menu--item-link is--link',
593
+ href: linkUrl,
594
+ target: linkTarget,
595
+ ...linkOns
596
+ }, renderMenuTitle(item, itemList))
597
+ : (
598
+ routerLink
599
+ ? h(resolveComponent('router-link'), {
600
+ class: 'vxe-menu--item-link is--router',
601
+ to: routerLink,
602
+ target: linkTarget,
603
+ ...linkOns
604
+ }, {
605
+ default: () => renderMenuTitle(item, itemList)
606
+ })
607
+ : h('div', {
608
+ class: 'vxe-menu--item-link is--default',
609
+ ...linkOns
610
+ }, renderMenuTitle(item, itemList))
611
+ ),
472
612
  hasChild
473
613
  ? h('div', {
474
614
  class: 'vxe-menu--item-group'
475
- }, childList.map(child => renderDefaultChildren(child, childList)))
615
+ }, isExpandChild || menuInitMaps[itemId] ? childList.map(child => renderDefaultChildren(child, childList)) : [])
476
616
  : renderEmptyElement($xeMenu)
477
617
  ])
478
618
  }
479
619
 
480
620
  const renderCollapseChildren = (item: VxeMenuDefines.MenuItem, itemList: VxeMenuDefines.MenuItem[]): VNode => {
481
- const { itemId, itemKey, level, hasChild, isActive, isExactActive, routerLink, childList } = item
621
+ const { itemId, itemKey, level, hasChild, isActive, isExactActive, routerLink, linkUrl, linkTarget, childList } = item
482
622
  if (item.permissionCode) {
483
623
  if (!permission.checkVisible(item.permissionCode)) {
484
624
  return renderEmptyElement($xeMenu)
485
625
  }
486
626
  }
627
+ const linkOns = {
628
+ onContextmenu (evnt: MouseEvent) {
629
+ handleContextmenuEvent(evnt, item)
630
+ },
631
+ onClick (evnt: MouseEvent) {
632
+ handleClickMenu(evnt, item, itemList)
633
+ }
634
+ }
487
635
  return h('div', {
488
636
  key: itemKey,
489
637
  class: ['vxe-menu--item-wrapper', `vxe-menu--item-level${level}`, {
638
+ 'has--child': hasChild,
490
639
  'is--exact-active': isExactActive,
491
640
  'is--active': isActive
492
641
  }],
493
642
  'data-menu-id': itemId
494
643
  }, [
495
- routerLink
496
- ? h(resolveComponent('router-link'), {
497
- class: 'vxe-menu--item-link',
498
- to: routerLink,
499
- onContextmenu (evnt: MouseEvent) {
500
- handleContextmenuEvent(evnt, item)
501
- },
502
- onClick (evnt: MouseEvent) {
503
- handleClickMenu(evnt, item, itemList)
504
- }
505
- }, {
506
- default: () => renderMenuTitle(item, itemList)
507
- })
508
- : h('div', {
509
- class: 'vxe-menu--item-link',
510
- onContextmenu (evnt: MouseEvent) {
511
- handleContextmenuEvent(evnt, item)
512
- },
513
- onClick (evnt: MouseEvent) {
514
- handleClickMenu(evnt, item, itemList)
515
- }
516
- }, renderMenuTitle(item, itemList)),
644
+ linkUrl
645
+ ? h('a', {
646
+ class: 'vxe-menu--item-link is--link',
647
+ href: linkUrl,
648
+ target: linkTarget,
649
+ ...linkOns
650
+ }, renderMenuTitle(item, itemList))
651
+ : (
652
+ routerLink
653
+ ? h(resolveComponent('router-link'), {
654
+ class: 'vxe-menu--item-link is--router',
655
+ to: routerLink,
656
+ target: linkTarget,
657
+ ...linkOns
658
+ }, {
659
+ default: () => renderMenuTitle(item, itemList)
660
+ })
661
+ : h('div', {
662
+ class: 'vxe-menu--item-link is--default',
663
+ ...linkOns
664
+ }, renderMenuTitle(item, itemList))
665
+ ),
517
666
  hasChild
518
667
  ? h('div', {
519
668
  class: 'vxe-menu--item-group'
@@ -527,27 +676,45 @@ export default defineVxeComponent({
527
676
  const { initialized, menuList, collapseStyle, isEnterCollapse } = reactData
528
677
  const vSize = computeSize.value
529
678
  const isCollapsed = computeIsCollapsed.value
679
+ const currBorder = computeCurrBorder.value
680
+ const varStyle = computeVarStyle.value
681
+ const headerSlot = slots.header
682
+ const footerSlot = slots.footer
530
683
  let ons: Record<string, any> = {}
531
684
  if (collapseFixed) {
532
685
  ons = {
533
686
  onMouseenter: handleMenuMouseenter,
534
- onMouseover: handleMenuMouseover,
535
687
  onMouseleave: handleMenuMouseleave
536
688
  }
537
689
  }
690
+ const stParams = { collapsed: isCollapsed }
538
691
  return h('div', {
539
692
  ref: refElem,
540
693
  class: ['vxe-menu', {
694
+ [`border--${currBorder}`]: currBorder,
541
695
  [`size--${vSize}`]: vSize,
542
696
  'is--collapsed': isCollapsed,
543
697
  'is--loading': loading
544
698
  }]
545
699
  }, [
700
+ headerSlot
701
+ ? h('div', {
702
+ class: 'vxe-menu--header'
703
+ }, headerSlot(stParams))
704
+ : renderEmptyElement($xeMenu),
546
705
  h('div', {
547
- class: 'vxe-menu--item-list'
706
+ class: 'vxe-menu--body'
548
707
  }, menuList.map(child => isCollapsed ? renderCollapseChildren(child, menuList) : renderDefaultChildren(child, menuList))),
549
- initialized
708
+ footerSlot
550
709
  ? h('div', {
710
+ class: 'vxe-menu--footer'
711
+ }, footerSlot(stParams))
712
+ : renderEmptyElement($xeMenu),
713
+ h(Teleport, {
714
+ to: 'body',
715
+ disabled: !initialized
716
+ }, [
717
+ h('div', {
551
718
  ref: refCollapseElem,
552
719
  class: ['vxe-menu--collapse-wrapper', {
553
720
  [`size--${vSize}`]: vSize,
@@ -555,16 +722,26 @@ export default defineVxeComponent({
555
722
  'is--enter': isEnterCollapse,
556
723
  'is--loading': loading
557
724
  }],
558
- style: collapseStyle,
725
+ style: Object.assign({}, varStyle, collapseStyle),
559
726
  ...ons
560
- }, [
561
- isCollapsed
562
- ? h('div', {
563
- class: 'vxe-menu--item-list'
564
- }, menuList.map(child => renderDefaultChildren(child, menuList)))
565
- : renderEmptyElement($xeMenu)
566
- ])
567
- : renderEmptyElement($xeMenu),
727
+ }, isCollapsed
728
+ ? [
729
+ headerSlot
730
+ ? h('div', {
731
+ class: 'vxe-menu--header'
732
+ }, headerSlot(stParams))
733
+ : renderEmptyElement($xeMenu),
734
+ h('div', {
735
+ class: 'vxe-menu--body'
736
+ }, menuList.map(child => renderDefaultChildren(child, menuList))),
737
+ footerSlot
738
+ ? h('div', {
739
+ class: 'vxe-menu--footer'
740
+ }, footerSlot(stParams))
741
+ : renderEmptyElement($xeMenu)
742
+ ]
743
+ : [])
744
+ ]),
568
745
  /**
569
746
  * 加载中
570
747
  */
@@ -610,13 +787,6 @@ export default defineVxeComponent({
610
787
  })
611
788
 
612
789
  onBeforeUnmount(() => {
613
- const collapseEl = refCollapseElem.value
614
- if (collapseEl) {
615
- const parentNode = collapseEl.parentNode
616
- if (parentNode) {
617
- parentNode.removeChild(collapseEl)
618
- }
619
- }
620
790
  globalEvents.off($xeMenu, 'resize')
621
791
  XEUtils.assign(reactData, createReactData())
622
792
  XEUtils.assign(internalData, createInternalData())