From 8c94b7834685042d199cea5b3b7e4e8432a8d557 Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Thu, 26 Nov 2020 23:43:22 +0800 Subject: [PATCH] fix: menu overflowed error #3262 --- components/menu/__tests__/index.test.js | 2 +- components/vc-menu/DOMWrap.jsx | 30 +++++++++++++++++++------ components/vc-menu/FunctionProvider.jsx | 1 + components/vc-menu/Menu.jsx | 5 ++++- components/vc-menu/SubMenu.jsx | 6 +++-- components/vc-menu/util.js | 7 +++++- 6 files changed, 39 insertions(+), 12 deletions(-) diff --git a/components/menu/__tests__/index.test.js b/components/menu/__tests__/index.test.js index a19a5aff97..ed370bc103 100644 --- a/components/menu/__tests__/index.test.js +++ b/components/menu/__tests__/index.test.js @@ -477,7 +477,7 @@ describe('Menu', () => { }, 500); }); - fit('horizontal', async () => { + it('horizontal', async () => { const wrapper = mount( { render() { diff --git a/components/vc-menu/DOMWrap.jsx b/components/vc-menu/DOMWrap.jsx index d1427f9892..a7a6e65ef6 100644 --- a/components/vc-menu/DOMWrap.jsx +++ b/components/vc-menu/DOMWrap.jsx @@ -4,10 +4,12 @@ import SubMenu from './SubMenu'; import BaseMixin from '../_util/BaseMixin'; import { getWidth, setStyle, menuAllProps } from './util'; import { cloneElement } from '../_util/vnode'; -import { getPropsData, getAllProps, getSlot, findDOMNode } from '../_util/props-util'; +import { getAllProps, getSlot, findDOMNode } from '../_util/props-util'; const MENUITEM_OVERFLOWED_CLASSNAME = 'menuitem-overflowed'; const FLOAT_PRECISION_ADJUST = 0.5; +const MENUITEM_OVERFLOWED_UNI_KEY = 'MENUITEM_OVERFLOWED_UNI_KEY'; +const MENUITEM_OVERFLOWED_UNI_KEYS = [MENUITEM_OVERFLOWED_UNI_KEY]; const DOMWrap = { name: 'DOMWrap', @@ -136,6 +138,7 @@ const DOMWrap = { class: `${prefixCls}-overflowed-submenu`, key, style, + isOverflowedSubMenu: true, }; return {overflowedItems}; }, @@ -227,7 +230,8 @@ const DOMWrap = { const className = this.$attrs.class || ''; return (children || []).reduce((acc, childNode, index) => { let item = childNode; - const eventKey = getPropsData(childNode).eventKey; + const { extraProps = {} } = item.props || {}; + const { eventKey } = extraProps; if (this.mode === 'horizontal') { let overflowed = this.getOverflowedSubMenuItem(eventKey, []); if ( @@ -239,21 +243,33 @@ const DOMWrap = { childNode, // 这里修改 eventKey 是为了防止隐藏状态下还会触发 openkeys 事件 { - style: { display: 'none' }, - eventKey: `${eventKey}-hidden`, - class: MENUITEM_OVERFLOWED_CLASSNAME, + extraProps: { + ...extraProps, + style: { display: 'none' }, + eventKey: `${eventKey}-hidden`, + class: MENUITEM_OVERFLOWED_CLASSNAME, + parentUniKey: MENUITEM_OVERFLOWED_UNI_KEY, + parentUniKeys: MENUITEM_OVERFLOWED_UNI_KEYS, + }, }, ); } if (index === lastVisibleIndex + 1) { this.overflowedItems = children.slice(lastVisibleIndex + 1).map(c => { + const { extraProps = {} } = c.props || {}; + const { eventKey } = extraProps; return cloneElement( c, // children[index].key will become '.$key' in clone by default, // we have to overwrite with the correct key explicitly { - key: getPropsData(c).eventKey, - mode: 'vertical-left', + extraProps: { + ...extraProps, + key: eventKey, + mode: 'vertical-left', + parentUniKey: MENUITEM_OVERFLOWED_UNI_KEY, + parentUniKeys: MENUITEM_OVERFLOWED_UNI_KEYS, + }, }, ); }); diff --git a/components/vc-menu/FunctionProvider.jsx b/components/vc-menu/FunctionProvider.jsx index c8eb0d7e6c..fb34e9c16a 100644 --- a/components/vc-menu/FunctionProvider.jsx +++ b/components/vc-menu/FunctionProvider.jsx @@ -4,6 +4,7 @@ import { propTypes } from '../vc-progress/src/types'; export const injectExtraPropsKey = Symbol(); const FunctionProvider = { inheritAttrs: false, + isMenuProvider: true, props: { extraProps: propTypes.object, }, diff --git a/components/vc-menu/Menu.jsx b/components/vc-menu/Menu.jsx index f7812aac32..11639b7c1f 100644 --- a/components/vc-menu/Menu.jsx +++ b/components/vc-menu/Menu.jsx @@ -13,6 +13,7 @@ import { toRaw, watch, } from 'vue'; +import { isEqual } from 'lodash-es'; const Menu = { name: 'Menu', @@ -62,7 +63,9 @@ const Menu = { .reduce((allKeys, { parentUniKeys = [] }) => { return [...allKeys, ...toRaw(parentUniKeys)]; }, []); - selectedParentUniKeys.value = keys || []; + if (!isEqual(selectedParentUniKeys.value, keys)) { + selectedParentUniKeys.value = keys || []; + } }); const store = reactive({ selectedKeys, diff --git a/components/vc-menu/SubMenu.jsx b/components/vc-menu/SubMenu.jsx index 68c995dee7..d0baff301d 100644 --- a/components/vc-menu/SubMenu.jsx +++ b/components/vc-menu/SubMenu.jsx @@ -75,11 +75,14 @@ const SubMenu = defineComponent({ theme: PropTypes.string, parentUniKeys: PropTypes.array.def(() => []), parentUniKey: PropTypes.string, + isOverflowedSubMenu: PropTypes.looseBool.def(false), }, isSubMenu: true, setup(props) { - const uniKey = `sub_menu_${++indexGuid}`; + const uniKey = props.isOverflowedSubMenu + ? 'MENUITEM_OVERFLOWED_UNI_KEY' + : `sub_menu_${++indexGuid}`; const store = inject('menuStore', () => ({})); onMounted(() => { store.addChildrenInfo( @@ -439,7 +442,6 @@ const SubMenu = defineComponent({ [this.getDisabledClassName()]: props.disabled, [this.getSelectedClassName()]: this.isChildrenSelected || this.isChildrenSelected2(), }; - if (!this.internalMenuId) { if (props.eventKey) { this.internalMenuId = `${props.eventKey}$Menu`; diff --git a/components/vc-menu/util.js b/components/vc-menu/util.js index b292acd072..9321106826 100644 --- a/components/vc-menu/util.js +++ b/components/vc-menu/util.js @@ -40,7 +40,12 @@ export function loopMenuItemRecursively(children, keys, ret) { if (construct && isObject(construct)) { if ( !construct || - !(construct.isSubMenu || construct.isMenuItem || construct.isMenuItemGroup) + !( + construct.isSubMenu || + construct.isMenuItem || + construct.isMenuItemGroup || + construct.isMenuProvider + ) ) { return; }