fix: menu overflowed error #3262

pull/3271/head
tangjinzhou 2020-11-26 23:43:22 +08:00
parent f5cf7e0920
commit 8c94b78346
6 changed files with 39 additions and 12 deletions

View File

@ -477,7 +477,7 @@ describe('Menu', () => {
}, 500); }, 500);
}); });
fit('horizontal', async () => { it('horizontal', async () => {
const wrapper = mount( const wrapper = mount(
{ {
render() { render() {

View File

@ -4,10 +4,12 @@ import SubMenu from './SubMenu';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
import { getWidth, setStyle, menuAllProps } from './util'; import { getWidth, setStyle, menuAllProps } from './util';
import { cloneElement } from '../_util/vnode'; 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 MENUITEM_OVERFLOWED_CLASSNAME = 'menuitem-overflowed';
const FLOAT_PRECISION_ADJUST = 0.5; 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 = { const DOMWrap = {
name: 'DOMWrap', name: 'DOMWrap',
@ -136,6 +138,7 @@ const DOMWrap = {
class: `${prefixCls}-overflowed-submenu`, class: `${prefixCls}-overflowed-submenu`,
key, key,
style, style,
isOverflowedSubMenu: true,
}; };
return <SubMenu {...subMenuProps}>{overflowedItems}</SubMenu>; return <SubMenu {...subMenuProps}>{overflowedItems}</SubMenu>;
}, },
@ -227,7 +230,8 @@ const DOMWrap = {
const className = this.$attrs.class || ''; const className = this.$attrs.class || '';
return (children || []).reduce((acc, childNode, index) => { return (children || []).reduce((acc, childNode, index) => {
let item = childNode; let item = childNode;
const eventKey = getPropsData(childNode).eventKey; const { extraProps = {} } = item.props || {};
const { eventKey } = extraProps;
if (this.mode === 'horizontal') { if (this.mode === 'horizontal') {
let overflowed = this.getOverflowedSubMenuItem(eventKey, []); let overflowed = this.getOverflowedSubMenuItem(eventKey, []);
if ( if (
@ -239,21 +243,33 @@ const DOMWrap = {
childNode, childNode,
// eventKey openkeys // eventKey openkeys
{ {
style: { display: 'none' }, extraProps: {
eventKey: `${eventKey}-hidden`, ...extraProps,
class: MENUITEM_OVERFLOWED_CLASSNAME, style: { display: 'none' },
eventKey: `${eventKey}-hidden`,
class: MENUITEM_OVERFLOWED_CLASSNAME,
parentUniKey: MENUITEM_OVERFLOWED_UNI_KEY,
parentUniKeys: MENUITEM_OVERFLOWED_UNI_KEYS,
},
}, },
); );
} }
if (index === lastVisibleIndex + 1) { if (index === lastVisibleIndex + 1) {
this.overflowedItems = children.slice(lastVisibleIndex + 1).map(c => { this.overflowedItems = children.slice(lastVisibleIndex + 1).map(c => {
const { extraProps = {} } = c.props || {};
const { eventKey } = extraProps;
return cloneElement( return cloneElement(
c, c,
// children[index].key will become '.$key' in clone by default, // children[index].key will become '.$key' in clone by default,
// we have to overwrite with the correct key explicitly // we have to overwrite with the correct key explicitly
{ {
key: getPropsData(c).eventKey, extraProps: {
mode: 'vertical-left', ...extraProps,
key: eventKey,
mode: 'vertical-left',
parentUniKey: MENUITEM_OVERFLOWED_UNI_KEY,
parentUniKeys: MENUITEM_OVERFLOWED_UNI_KEYS,
},
}, },
); );
}); });

View File

@ -4,6 +4,7 @@ import { propTypes } from '../vc-progress/src/types';
export const injectExtraPropsKey = Symbol(); export const injectExtraPropsKey = Symbol();
const FunctionProvider = { const FunctionProvider = {
inheritAttrs: false, inheritAttrs: false,
isMenuProvider: true,
props: { props: {
extraProps: propTypes.object, extraProps: propTypes.object,
}, },

View File

@ -13,6 +13,7 @@ import {
toRaw, toRaw,
watch, watch,
} from 'vue'; } from 'vue';
import { isEqual } from 'lodash-es';
const Menu = { const Menu = {
name: 'Menu', name: 'Menu',
@ -62,7 +63,9 @@ const Menu = {
.reduce((allKeys, { parentUniKeys = [] }) => { .reduce((allKeys, { parentUniKeys = [] }) => {
return [...allKeys, ...toRaw(parentUniKeys)]; return [...allKeys, ...toRaw(parentUniKeys)];
}, []); }, []);
selectedParentUniKeys.value = keys || []; if (!isEqual(selectedParentUniKeys.value, keys)) {
selectedParentUniKeys.value = keys || [];
}
}); });
const store = reactive({ const store = reactive({
selectedKeys, selectedKeys,

View File

@ -75,11 +75,14 @@ const SubMenu = defineComponent({
theme: PropTypes.string, theme: PropTypes.string,
parentUniKeys: PropTypes.array.def(() => []), parentUniKeys: PropTypes.array.def(() => []),
parentUniKey: PropTypes.string, parentUniKey: PropTypes.string,
isOverflowedSubMenu: PropTypes.looseBool.def(false),
}, },
isSubMenu: true, isSubMenu: true,
setup(props) { setup(props) {
const uniKey = `sub_menu_${++indexGuid}`; const uniKey = props.isOverflowedSubMenu
? 'MENUITEM_OVERFLOWED_UNI_KEY'
: `sub_menu_${++indexGuid}`;
const store = inject('menuStore', () => ({})); const store = inject('menuStore', () => ({}));
onMounted(() => { onMounted(() => {
store.addChildrenInfo( store.addChildrenInfo(
@ -439,7 +442,6 @@ const SubMenu = defineComponent({
[this.getDisabledClassName()]: props.disabled, [this.getDisabledClassName()]: props.disabled,
[this.getSelectedClassName()]: this.isChildrenSelected || this.isChildrenSelected2(), [this.getSelectedClassName()]: this.isChildrenSelected || this.isChildrenSelected2(),
}; };
if (!this.internalMenuId) { if (!this.internalMenuId) {
if (props.eventKey) { if (props.eventKey) {
this.internalMenuId = `${props.eventKey}$Menu`; this.internalMenuId = `${props.eventKey}$Menu`;

View File

@ -40,7 +40,12 @@ export function loopMenuItemRecursively(children, keys, ret) {
if (construct && isObject(construct)) { if (construct && isObject(construct)) {
if ( if (
!construct || !construct ||
!(construct.isSubMenu || construct.isMenuItem || construct.isMenuItemGroup) !(
construct.isSubMenu ||
construct.isMenuItem ||
construct.isMenuItemGroup ||
construct.isMenuProvider
)
) { ) {
return; return;
} }