From da6d243e9e0cd558412f652fa7d08b56cba8790a Mon Sep 17 00:00:00 2001
From: tangjinzhou <415800467@qq.com>
Date: Mon, 23 Nov 2020 00:21:18 -0600
Subject: [PATCH] Perf menu2.0 (#3243)
close #3231 #3188
---
CHANGELOG.zh-CN.md | 1 -
antdv-demo | 2 +-
components/menu/SubMenu.tsx | 7 +-
.../__tests__/__snapshots__/demo.test.js.snap | 214 ++----------------
components/menu/__tests__/index.test.js | 144 ++++++------
components/menu/index.tsx | 6 +-
components/menu/style/index.less | 2 +-
components/table/filterDropdown.tsx | 6 +-
components/table/interface.ts | 8 +-
components/table/style/size.less | 4 +-
.../__tests__/__snapshots__/demo.test.js.snap | 14 ++
components/vc-mentions/src/DropdownMenu.jsx | 5 +-
components/vc-menu/DOMWrap.jsx | 4 +-
components/vc-menu/Divider.jsx | 2 +-
components/vc-menu/FunctionProvider.jsx | 13 +-
components/vc-menu/InjectExtraProps.js | 42 ++++
components/vc-menu/Menu.jsx | 143 +++++++-----
components/vc-menu/MenuItem.jsx | 79 +++----
components/vc-menu/SubMenu.jsx | 209 ++++++++---------
components/vc-menu/SubPopupMenu.jsx | 114 +++++-----
components/vc-menu/commonPropsType.js | 4 +-
components/vc-menu/util.js | 32 +--
examples/App.vue | 57 ++---
23 files changed, 497 insertions(+), 615 deletions(-)
create mode 100644 components/vc-menu/InjectExtraProps.js
diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md
index 9752d59982..72f1734356 100644
--- a/CHANGELOG.zh-CN.md
+++ b/CHANGELOG.zh-CN.md
@@ -10,7 +10,6 @@
---
-
## 2.0.0-rc.1
`2020-11-14`
diff --git a/antdv-demo b/antdv-demo
index 7cccccbb55..ef82783952 160000
--- a/antdv-demo
+++ b/antdv-demo
@@ -1 +1 @@
-Subproject commit 7cccccbb5571e61b35aca0d454eb83bc5924995e
+Subproject commit ef827839524b6f1ed427aefa082adb09ac2cc95f
diff --git a/components/menu/SubMenu.tsx b/components/menu/SubMenu.tsx
index 10f2f13695..24edc9dbff 100644
--- a/components/menu/SubMenu.tsx
+++ b/components/menu/SubMenu.tsx
@@ -1,8 +1,6 @@
import { defineComponent, inject } from 'vue';
import { SubMenu as VcSubMenu } from '../vc-menu';
import classNames from '../_util/classNames';
-import Omit from 'omit.js';
-import { getSlot } from '../_util/props-util';
import { injectExtraPropsKey } from '../vc-menu/FunctionProvider';
export type MenuTheme = 'light' | 'dark';
@@ -38,8 +36,7 @@ export default defineComponent({
popupClassName: classNames(`${rootPrefixCls}-${antdMenuTheme}`, popupClassName),
ref: 'subMenu',
...$attrs,
- ...Omit($slots, ['default']),
- };
- return {getSlot(this)};
+ } as any;
+ return ;
},
});
diff --git a/components/menu/__tests__/__snapshots__/demo.test.js.snap b/components/menu/__tests__/__snapshots__/demo.test.js.snap
index 2413edfe2b..4266989b95 100644
--- a/components/menu/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/menu/__tests__/__snapshots__/demo.test.js.snap
@@ -6,8 +6,7 @@ exports[`renders ./antdv-demo/docs/menu/demo/horizontal.md correctly 1`] = `
@@ -17,8 +16,7 @@ exports[`renders ./antdv-demo/docs/menu/demo/horizontal.md correctly 1`] = `
@@ -28,22 +26,19 @@ exports[`renders ./antdv-demo/docs/menu/demo/horizontal.md correctly 1`] = `
@@ -53,8 +48,7 @@ exports[`renders ./antdv-demo/docs/menu/demo/horizontal.md correctly 1`] = `
@@ -98,52 +92,12 @@ exports[`renders ./antdv-demo/docs/menu/demo/inline.md correctly 1`] = `
@@ -169,7 +123,7 @@ exports[`renders ./antdv-demo/docs/menu/demo/inline-collapsed.md correctly 1`] =
@@ -479,15 +313,13 @@ exports[`renders ./antdv-demo/docs/menu/demo/vertical.md correctly 1`] = `
diff --git a/components/menu/__tests__/index.test.js b/components/menu/__tests__/index.test.js
index e3716008c0..a19a5aff97 100644
--- a/components/menu/__tests__/index.test.js
+++ b/components/menu/__tests__/index.test.js
@@ -52,7 +52,7 @@ describe('Menu', () => {
{ attachTo: 'body', sync: false },
);
await asyncExpect(() => {
- expect($$('.ant-menu-submenu-selected').length).toBe(2);
+ expect($$('.ant-menu-submenu-selected').length).toBe(1);
});
});
it('should accept defaultOpenKeys in mode horizontal', async () => {
@@ -73,7 +73,7 @@ describe('Menu', () => {
{ attachTo: 'body', sync: false },
);
await asyncExpect(() => {
- expect($$('.ant-menu-sub')[0].parentElement.style.display).toBe('none');
+ expect($$('.ant-menu-sub')[0].parentElement.style.display).not.toBe('none');
});
});
@@ -121,44 +121,44 @@ describe('Menu', () => {
});
});
- // it('horizontal', async () => {
- // const wrapper = mount(
- // {
- // props: {
- // openKeys: {
- // type: Array,
- // default() {
- // return ['1'];
- // },
- // },
- // },
- // render() {
- // return (
- //
- // );
- // },
- // },
- // { attachTo: 'body', sync: false },
- // );
- // await asyncExpect(() => {
- // expect($$('.ant-menu-sub')[0].parentElement.style.display).not.toBe('none');
- // }, 100);
- // wrapper.setProps({ openKeys: [] });
- // await asyncExpect(() => {
- // expect($$('.ant-menu-sub')[0].parentElement.style.display).toBe('none');
- // }, 500);
+ it('horizontal', async () => {
+ const wrapper = mount(
+ {
+ props: {
+ openKeys: {
+ type: Array,
+ default() {
+ return ['1'];
+ },
+ },
+ },
+ render() {
+ return (
+
+ );
+ },
+ },
+ { attachTo: 'body', sync: false },
+ );
+ await asyncExpect(() => {
+ expect($$('.ant-menu-sub')[0].parentElement.style.display).not.toBe('none');
+ });
+ wrapper.setProps({ openKeys: [] });
+ await asyncExpect(() => {
+ expect($$('.ant-menu-sub')[0].parentElement.style.display).toBe('none');
+ }, 500);
- // wrapper.setProps({ openKeys: ['1'] });
- // await asyncExpect(() => {
- // expect($$('.ant-menu-sub')[0].parentElement.style.display).not.toBe('none');
- // }, 0);
- // });
+ wrapper.setProps({ openKeys: ['1'] });
+ await asyncExpect(() => {
+ expect($$('.ant-menu-sub')[0].parentElement.style.display).not.toBe('none');
+ }, 0);
+ });
it('inline', async () => {
const wrapper = mount(
@@ -382,7 +382,7 @@ describe('Menu', () => {
{ attachTo: 'body', sync: false },
);
await asyncExpect(() => {
- expect(wrapper.findAll('.ant-menu-sub').length).not.toBe(0);
+ expect(wrapper.findAll('.ant-menu-sub').length).toBe(0);
});
wrapper.setProps({ inlineCollapsed: true });
await asyncExpect(() => {
@@ -433,7 +433,7 @@ describe('Menu', () => {
{ attachTo: 'body', sync: false },
);
await asyncExpect(() => {
- expect($$('.ant-menu-sub')[0].style.display).toBe('none');
+ expect($$('.ant-menu-sub').length).toBe(0);
toggleMenu(wrapper, 0, 'click');
}, 0);
await asyncExpect(() => {
@@ -464,7 +464,7 @@ describe('Menu', () => {
{ attachTo: 'body', sync: false },
);
await asyncExpect(() => {
- expect($$('.ant-menu-sub')[0].parentElement.style.display).toBe('none');
+ expect($$('.ant-menu-sub').length).toBe(0);
toggleMenu(wrapper, 0, 'mouseenter');
}, 0);
await asyncExpect(() => {
@@ -477,36 +477,36 @@ describe('Menu', () => {
}, 500);
});
- // it('horizontal', async () => {
- // const wrapper = mount(
- // {
- // render() {
- // return (
- //
- // );
- // },
- // },
- // { attachTo: 'body', sync: false },
- // );
- // await asyncExpect(() => {
- // // expect($$('.ant-menu-sub').length).toBe(0);
- // toggleMenu(wrapper, 3, 'mouseenter');
- // }, 0);
- // await asyncExpect(() => {
- // // expect($$('.ant-menu-sub').length).toBe(1);
- // expect($$('.ant-menu-sub')[0].style.display).not.toBe('none');
- // toggleMenu(wrapper, 1, 'mouseleave');
- // }, 500);
- // await asyncExpect(() => {
- // expect($$('.ant-menu-sub')[0].style.display).toBe('none');
- // }, 500);
- // });
+ fit('horizontal', async () => {
+ const wrapper = mount(
+ {
+ render() {
+ return (
+
+ );
+ },
+ },
+ { attachTo: 'body', sync: false },
+ );
+ await asyncExpect(() => {
+ expect($$('.ant-menu-sub').length).toBe(0);
+ toggleMenu(wrapper, 1, 'mouseenter');
+ }, 100);
+ await asyncExpect(() => {
+ expect($$('.ant-menu-sub').length).toBe(1);
+ expect($$('.ant-menu-sub')[0].parentElement.style.display).not.toBe('none');
+ toggleMenu(wrapper, 1, 'mouseleave');
+ }, 500);
+ await asyncExpect(() => {
+ expect($$('.ant-menu-sub')[0].parentElement.style.display).toBe('none');
+ }, 500);
+ });
});
it('inline title', async () => {
diff --git a/components/menu/index.tsx b/components/menu/index.tsx
index 467bba866c..842ace832f 100644
--- a/components/menu/index.tsx
+++ b/components/menu/index.tsx
@@ -6,7 +6,7 @@ import PropTypes from '../_util/vue-types';
import animation from '../_util/openAnimation';
import warning from '../_util/warning';
import Item from './MenuItem';
-import { hasProp, getOptionProps, getSlot } from '../_util/props-util';
+import { hasProp, getOptionProps } from '../_util/props-util';
import BaseMixin from '../_util/BaseMixin';
import commonPropsType from '../vc-menu/commonPropsType';
import { defaultConfigProvider } from '../config-provider';
@@ -275,7 +275,7 @@ const Menu = defineComponent({
onOpenChange: this.handleOpenChange,
onMouseenter: this.handleMouseEnter,
onTransitionend: this.handleTransitionEnd,
- children: getSlot(this),
+ // children: getSlot(this),
};
if (!hasProp(this, 'selectedKeys')) {
delete menuProps.selectedKeys;
@@ -300,7 +300,7 @@ const Menu = defineComponent({
menuProps.openKeys = [];
}
- return ;
+ return ;
},
});
diff --git a/components/menu/style/index.less b/components/menu/style/index.less
index fd214c05ba..90c9cbda81 100644
--- a/components/menu/style/index.less
+++ b/components/menu/style/index.less
@@ -190,7 +190,7 @@
&-popup {
position: absolute;
z-index: @zindex-dropdown;
- background: @menu-popup-bg;
+ // background: @menu-popup-bg;
border-radius: @border-radius-base;
.submenu-title-wrapper {
diff --git a/components/table/filterDropdown.tsx b/components/table/filterDropdown.tsx
index 0d3e3de148..e0cb5a0a13 100755
--- a/components/table/filterDropdown.tsx
+++ b/components/table/filterDropdown.tsx
@@ -228,7 +228,6 @@ export default defineComponent({
const { column } = this;
const { sSelectedKeys: selectedKeys } = this;
const multiple = 'filterMultiple' in column ? column.filterMultiple : true;
-
const input = multiple ? (
= 0} />
) : (
@@ -281,8 +280,9 @@ export default defineComponent({
onDeselect={this.setSelectedKeys}
selectedKeys={originSelectedKeys}
getPopupContainer={getPopupContainer}
- children={this.renderMenus(column.filters)}
- >
+ >
+ {this.renderMenus(column.filters)}
+
{locale.filterConfirm}
diff --git a/components/table/interface.ts b/components/table/interface.ts
index 6637ca8693..bf721cdc20 100644
--- a/components/table/interface.ts
+++ b/components/table/interface.ts
@@ -181,10 +181,10 @@ export interface TableState {
}
export interface TransformCellTextProps {
- text: any,
- column: ColumnProps,
- record: any,
- index: number
+ text: any;
+ column: ColumnProps;
+ record: any;
+ index: number;
}
// export type SelectionItemSelectFn = (key: string[]) => any;
diff --git a/components/table/style/size.less b/components/table/style/size.less
index ff2a532f07..e4da470307 100644
--- a/components/table/style/size.less
+++ b/components/table/style/size.less
@@ -32,13 +32,11 @@
}
tr.@{table-prefix-cls}-expanded-row td > .@{table-prefix-cls}-wrapper {
- margin: -@padding-vertical -@table-padding-horizontal / 2 -@padding-vertical -
- 1px;
+ margin: -@padding-vertical -@table-padding-horizontal / 2 -@padding-vertical - 1px;
}
}
}
-
// ================================================================
// = Middle =
// ================================================================
diff --git a/components/tag/__tests__/__snapshots__/demo.test.js.snap b/components/tag/__tests__/__snapshots__/demo.test.js.snap
index 35f0d8a978..09047fa92b 100644
--- a/components/tag/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/tag/__tests__/__snapshots__/demo.test.js.snap
@@ -27,3 +27,17 @@ exports[`renders ./antdv-demo/docs/tag/demo/controlled.md correctly 1`] = `
`;
exports[`renders ./antdv-demo/docs/tag/demo/hot-tags.md correctly 1`] = `Categories:MoviesBooksMusicSports
`;
+
+exports[`renders ./antdv-demo/docs/tag/demo/status.md correctly 1`] = `
+Without icon
+successprocessingerrorwarningdefault
+With icon
+ success
+ processing
+ error
+ warning
+ waiting
+ stop
+
+
+`;
diff --git a/components/vc-mentions/src/DropdownMenu.jsx b/components/vc-mentions/src/DropdownMenu.jsx
index 023d36601e..e927452bbb 100644
--- a/components/vc-mentions/src/DropdownMenu.jsx
+++ b/components/vc-mentions/src/DropdownMenu.jsx
@@ -37,7 +37,8 @@ export default {
}}
onBlur={onBlur}
onFocus={onFocus}
- children={[
+ >
+ {[
...options.map((option, index) => {
const { value, disabled, children } = option;
return (
@@ -58,7 +59,7 @@ export default {
),
].filter(Boolean)}
- />
+
);
},
};
diff --git a/components/vc-menu/DOMWrap.jsx b/components/vc-menu/DOMWrap.jsx
index f5ad7b730b..d1427f9892 100644
--- a/components/vc-menu/DOMWrap.jsx
+++ b/components/vc-menu/DOMWrap.jsx
@@ -100,7 +100,8 @@ const DOMWrap = {
// put all the overflowed item inside a submenu
// with a title of overflow indicator ('...')
const copy = getSlot(this)[0];
- const { title, ...rest } = getAllProps(copy); // eslint-disable-line no-unused-vars
+ const allProps = getAllProps(copy) || {};
+ const { title, extraProps, ...rest } = { ...allProps, ...allProps.extraProps }; // eslint-disable-line no-unused-vars
let style = {};
let key = `${keyPrefix}-overflowed-indicator`;
let eventKey = `${keyPrefix}-overflowed-indicator`;
@@ -136,7 +137,6 @@ const DOMWrap = {
key,
style,
};
-
return {overflowedItems};
},
diff --git a/components/vc-menu/Divider.jsx b/components/vc-menu/Divider.jsx
index 45b6f457ab..136a2a97f2 100644
--- a/components/vc-menu/Divider.jsx
+++ b/components/vc-menu/Divider.jsx
@@ -16,7 +16,7 @@ export default {
};
},
render() {
- const { rootPrefixCls } = {...this.$props, ...this.injectExtraProps};
+ const { rootPrefixCls } = { ...this.$props, ...this.injectExtraProps };
const { class: className = '', style } = this.$attrs;
return ;
},
diff --git a/components/vc-menu/FunctionProvider.jsx b/components/vc-menu/FunctionProvider.jsx
index 7e41eafc2d..c8eb0d7e6c 100644
--- a/components/vc-menu/FunctionProvider.jsx
+++ b/components/vc-menu/FunctionProvider.jsx
@@ -1,10 +1,17 @@
// import PropTypes from '../_util/vue-types';
-import { provide, reactive } from 'vue';
+import { computed, provide } from 'vue';
+import { propTypes } from '../vc-progress/src/types';
export const injectExtraPropsKey = Symbol();
const FunctionProvider = {
inheritAttrs: false,
- setup(props, { slots, attrs }) {
- provide(injectExtraPropsKey, reactive(attrs));
+ props: {
+ extraProps: propTypes.object,
+ },
+ setup(props, { slots }) {
+ provide(
+ injectExtraPropsKey,
+ computed(() => props.extraProps),
+ );
return () => slots.default?.();
},
};
diff --git a/components/vc-menu/InjectExtraProps.js b/components/vc-menu/InjectExtraProps.js
new file mode 100644
index 0000000000..c1e0a67da3
--- /dev/null
+++ b/components/vc-menu/InjectExtraProps.js
@@ -0,0 +1,42 @@
+import { createVNode, defineComponent, inject, provide } from 'vue';
+import { injectExtraPropsKey } from './FunctionProvider';
+
+export default function wrapWithConnect(WrappedComponent) {
+ const tempProps = WrappedComponent.props || {};
+ const props = {};
+ Object.keys(tempProps).forEach(k => {
+ props[k] = { ...tempProps[k], required: false };
+ });
+ const Connect = {
+ name: `Connect_${WrappedComponent.name}`,
+ inheritAttrs: false,
+ props,
+ setup(props) {
+ provide(injectExtraPropsKey, undefined); // 断掉 injectExtraPropsKey 的依赖
+ return {
+ props,
+ injectExtraProps: injectExtraPropsKey ? inject(injectExtraPropsKey, () => ({})) : {},
+ };
+ },
+ methods: {
+ getWrappedInstance() {
+ return this.$refs.wrappedInstance;
+ },
+ },
+ render() {
+ const { $slots = {}, $attrs } = this;
+ const props = { ...this.props, ...this.injectExtraProps };
+ const wrapProps = {
+ ...$attrs,
+ ...props,
+ ref: 'wrappedInstance',
+ };
+ // const slots = {};
+ // for (let [key, value] of Object.entries($slots)) {
+ // slots[key] = () => value();
+ // }
+ return createVNode(WrappedComponent, wrapProps, $slots);
+ },
+ };
+ return defineComponent(Connect);
+}
diff --git a/components/vc-menu/Menu.jsx b/components/vc-menu/Menu.jsx
index cc88bd8cd3..f7812aac32 100644
--- a/components/vc-menu/Menu.jsx
+++ b/components/vc-menu/Menu.jsx
@@ -1,10 +1,18 @@
import PropTypes from '../_util/vue-types';
-import { Provider, create } from '../_util/store';
-import { default as SubPopupMenu, getActiveKey } from './SubPopupMenu';
+import { default as SubPopupMenu } from './SubPopupMenu';
import BaseMixin from '../_util/BaseMixin';
-import hasProp, { getOptionProps, getComponent, filterEmpty } from '../_util/props-util';
+import hasProp, { getOptionProps, getComponent } from '../_util/props-util';
import commonPropsType from './commonPropsType';
-import { defineComponent, provide } from 'vue';
+import {
+ computed,
+ defineComponent,
+ getCurrentInstance,
+ provide,
+ reactive,
+ ref,
+ toRaw,
+ watch,
+} from 'vue';
const Menu = {
name: 'Menu',
@@ -15,43 +23,81 @@ const Menu = {
selectable: PropTypes.looseBool.def(true),
},
mixins: [BaseMixin],
- data() {
- const props = getOptionProps(this);
- let selectedKeys = props.defaultSelectedKeys;
- let openKeys = props.defaultOpenKeys;
- if ('selectedKeys' in props) {
- selectedKeys = props.selectedKeys || [];
- }
- if ('openKeys' in props) {
- openKeys = props.openKeys || [];
- }
-
- this.store = create({
+ setup(props) {
+ const menuChildrenInfo = reactive({});
+ const selectedKeys = ref(props.selectedKeys || props.defaultSelectedKeys || []);
+ const openKeys = ref(props.openKeys || props.defaultOpenKeys || []);
+ // computed(() => {
+ // return props.openKeys || props.defaultOpenKeys || [];
+ // });
+ watch(
+ () => props.selectedKeys,
+ () => {
+ selectedKeys.value = props.selectedKeys;
+ },
+ );
+ watch(
+ () => props.openKeys,
+ () => {
+ openKeys.value = props.openKeys;
+ },
+ );
+ const activeKey = reactive({
+ '0-menu-': props.activeKey,
+ });
+ const defaultActiveFirst = reactive({});
+ const addChildrenInfo = (key, info) => {
+ menuChildrenInfo[key] = info;
+ };
+ const removeChildrenInfo = key => {
+ delete menuChildrenInfo[key];
+ };
+ const getActiveKey = key => {
+ return key;
+ }; // TODO
+ const selectedParentUniKeys = ref([]);
+ watch(menuChildrenInfo, () => {
+ const keys = Object.values(menuChildrenInfo)
+ .filter(info => info.isSelected)
+ .reduce((allKeys, { parentUniKeys = [] }) => {
+ return [...allKeys, ...toRaw(parentUniKeys)];
+ }, []);
+ selectedParentUniKeys.value = keys || [];
+ });
+ const store = reactive({
selectedKeys,
openKeys,
- activeKey: {
- '0-menu-': getActiveKey({ ...props, children: props.children || [] }, props.activeKey),
- },
+ activeKey,
+ defaultActiveFirst,
+ menuChildrenInfo,
+ selectedParentUniKeys,
+ addChildrenInfo,
+ removeChildrenInfo,
+ getActiveKey,
});
-
- // this.isRootMenu = true // 声明在props上
- return {};
- },
- created() {
- provide('parentMenu', this);
- },
- mounted() {
- this.updateMiniStore();
- },
- updated() {
- this.updateMiniStore();
+ const ins = getCurrentInstance();
+ const getEl = () => {
+ return ins.vnode.el;
+ };
+ provide('menuStore', store);
+ provide(
+ 'parentMenu',
+ reactive({
+ isRootMenu: computed(() => props.isRootMenu),
+ getPopupContainer: computed(() => props.getPopupContainer),
+ getEl,
+ }),
+ );
+ return {
+ store,
+ };
},
methods: {
handleSelect(selectInfo) {
const props = this.$props;
if (props.selectable) {
// root menu
- let selectedKeys = this.store.getState().selectedKeys;
+ let selectedKeys = this.store.selectedKeys;
const selectedKey = selectInfo.key;
if (props.multiple) {
selectedKeys = selectedKeys.concat([selectedKey]);
@@ -59,9 +105,7 @@ const Menu = {
selectedKeys = [selectedKey];
}
if (!hasProp(this, 'selectedKeys')) {
- this.store.setState({
- selectedKeys,
- });
+ this.store.selectedKeys = selectedKeys;
}
this.__emit('select', {
...selectInfo,
@@ -80,7 +124,7 @@ const Menu = {
this.innerMenu.getWrappedInstance().onKeyDown(e, callback);
},
onOpenChange(event) {
- const openKeys = this.store.getState().openKeys.concat();
+ const openKeys = this.store.openKeys.concat();
let changed = false;
const processSingle = e => {
let oneChanged = false;
@@ -106,7 +150,7 @@ const Menu = {
}
if (changed) {
if (!hasProp(this, 'openKeys')) {
- this.store.setState({ openKeys });
+ this.store.openKeys = openKeys;
}
this.__emit('openChange', openKeys);
}
@@ -115,16 +159,14 @@ const Menu = {
handleDeselect(selectInfo) {
const props = this.$props;
if (props.selectable) {
- const selectedKeys = this.store.getState().selectedKeys.concat();
+ const selectedKeys = this.store.selectedKeys.concat();
const selectedKey = selectInfo.key;
const index = selectedKeys.indexOf(selectedKey);
if (index !== -1) {
selectedKeys.splice(index, 1);
}
if (!hasProp(this, 'selectedKeys')) {
- this.store.setState({
- selectedKeys,
- });
+ this.store.selectedKeys = selectedKeys;
}
this.__emit('deselect', {
...selectInfo,
@@ -142,19 +184,6 @@ const Menu = {
}
return transitionName;
},
- updateMiniStore() {
- const props = getOptionProps(this);
- if ('selectedKeys' in props) {
- this.store.setState({
- selectedKeys: props.selectedKeys || [],
- });
- }
- if ('openKeys' in props) {
- this.store.setState({
- openKeys: props.openKeys || [],
- });
- }
- },
saveInnerMenu(ref) {
this.innerMenu = ref;
},
@@ -171,16 +200,14 @@ const Menu = {
expandIcon: getComponent(this, 'expandIcon', props),
overflowedIndicator: getComponent(this, 'overflowedIndicator', props) || ···,
openTransitionName: this.getOpenTransitionName(),
- children: filterEmpty(props.children),
onClick: this.handleClick,
onOpenChange: this.onOpenChange,
onDeselect: this.handleDeselect,
onSelect: this.handleSelect,
ref: this.saveInnerMenu,
+ store: this.store,
};
-
- const subPopupMenu = ;
- return {subPopupMenu};
+ return ;
},
};
diff --git a/components/vc-menu/MenuItem.jsx b/components/vc-menu/MenuItem.jsx
index d9b4424963..0750b1178c 100644
--- a/components/vc-menu/MenuItem.jsx
+++ b/components/vc-menu/MenuItem.jsx
@@ -2,11 +2,10 @@ import PropTypes from '../_util/vue-types';
import KeyCode from '../_util/KeyCode';
import BaseMixin from '../_util/BaseMixin';
import scrollIntoView from 'dom-scroll-into-view';
-import { connect } from '../_util/store';
import { noop, menuAllProps } from './util';
import { getComponent, getSlot, findDOMNode } from '../_util/props-util';
-import { inject } from 'vue';
-import { injectExtraPropsKey } from './FunctionProvider';
+import { computed, defineComponent, inject, onBeforeUnmount, onMounted } from 'vue';
+import InjectExtraProps from './InjectExtraProps';
const props = {
attribute: PropTypes.object,
rootPrefixCls: PropTypes.string,
@@ -21,36 +20,56 @@ const props = {
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']),
multiple: PropTypes.looseBool,
value: PropTypes.any,
- isSelected: PropTypes.looseBool,
manualRef: PropTypes.func.def(noop),
role: PropTypes.any,
subMenuKey: PropTypes.string,
itemIcon: PropTypes.any,
+ parentUniKeys: PropTypes.array.def(() => []),
+ parentUniKey: PropTypes.string,
// clearSubMenuTimers: PropTypes.func.def(noop),
};
-const MenuItem = {
+let indexGuid = 0;
+const MenuItem = defineComponent({
name: 'AMenuItem',
+ mixins: [BaseMixin],
inheritAttrs: false,
props,
- mixins: [BaseMixin],
isMenuItem: true,
- setup() {
- return { parentMenu: inject('parentMenu', undefined) };
+ setup(props) {
+ const uniKey = `menu_item_${++indexGuid}`;
+ const store = inject('menuStore', () => ({}));
+ const isSelected = computed(() => store.selectedKeys.indexOf(props.eventKey) !== -1);
+ onMounted(() => {
+ store.addChildrenInfo(
+ uniKey,
+ computed(() => ({
+ parentUniKeys: props.parentUniKeys,
+ parentUniKey: props.parentUniKey,
+ eventKey: props.eventKey,
+ isSelected: isSelected.value,
+ disabled: props.disabled,
+ })),
+ );
+ });
+ onBeforeUnmount(() => {
+ store.removeChildrenInfo(uniKey);
+ });
+
+ return {
+ parentMenu: inject('parentMenu', undefined),
+ isSelected,
+ };
},
created() {
this.prevActive = this.active;
// invoke customized ref to expose component to mixin
this.callRef();
},
- mounted() {
- this.updateParentMenuSelectedStatus();
- },
updated() {
- this.updateParentMenuSelectedStatus();
this.$nextTick(() => {
const { active, parentMenu, eventKey } = this;
if (!this.prevActive && active && (!parentMenu || !parentMenu[`scrolled-${eventKey}`])) {
- scrollIntoView(findDOMNode(this.node), findDOMNode(parentMenu), {
+ scrollIntoView(findDOMNode(this.node), parentMenu.getEl(), {
onlyScrollIfNeeded: true,
});
parentMenu[`scrolled-${eventKey}`] = true;
@@ -61,17 +80,7 @@ const MenuItem = {
});
this.callRef();
},
- beforeUnmount() {
- this.updateParentMenuSelectedStatus(false);
- const props = this.$props;
- this.__emit('destroy', props.eventKey);
- },
methods: {
- updateParentMenuSelectedStatus(status = this.isSelected) {
- if (this.parentMenu && this.parentMenu.setChildrenSelectedStatus) {
- this.parentMenu.setChildrenSelectedStatus(this.eventKey, status);
- }
- },
onKeyDown(e) {
const keyCode = e.keyCode;
if (keyCode === KeyCode.ENTER) {
@@ -105,11 +114,12 @@ const MenuItem = {
},
onClick(e) {
- const { eventKey, multiple, isSelected } = this.$props;
+ const { eventKey, multiple } = this.$props;
+ const { isSelected } = this;
const info = {
key: eventKey,
keyPath: [eventKey],
- item: { ...this.$props },
+ item: this,
domEvent: e,
};
@@ -156,8 +166,8 @@ const MenuItem = {
const className = {
[cls]: !!cls,
[this.getPrefixCls()]: true,
- [this.getActiveClassName()]: !props.disabled && props.active,
- [this.getSelectedClassName()]: props.isSelected,
+ [this.getActiveClassName()]: !props.disabled && this.active,
+ [this.getSelectedClassName()]: this.isSelected,
[this.getDisabledClassName()]: props.disabled,
};
let attrs = {
@@ -171,7 +181,7 @@ const MenuItem = {
attrs = {
...attrs,
role: 'option',
- 'aria-selected': props.isSelected,
+ 'aria-selected': this.isSelected,
};
} else if (props.role === null || props.role === 'none') {
// sometimes we want to specify role inside element
@@ -199,7 +209,6 @@ const MenuItem = {
...mouseEvent,
ref: this.saveNode,
};
- delete liProps.children;
return (
{getSlot(this)}
@@ -207,15 +216,7 @@ const MenuItem = {
);
},
-};
-
-const connected = connect(
- ({ activeKey, selectedKeys }, { eventKey, subMenuKey }) => ({
- active: activeKey[subMenuKey] === eventKey,
- isSelected: selectedKeys.indexOf(eventKey) !== -1,
- }),
- injectExtraPropsKey,
-)(MenuItem);
+});
-export default connected;
+export default InjectExtraProps(MenuItem);
export { props as menuItemProps };
diff --git a/components/vc-menu/SubMenu.jsx b/components/vc-menu/SubMenu.jsx
index 854431d5a6..68c995dee7 100644
--- a/components/vc-menu/SubMenu.jsx
+++ b/components/vc-menu/SubMenu.jsx
@@ -1,17 +1,25 @@
-import { inject, provide } from 'vue';
+import {
+ computed,
+ defineComponent,
+ getCurrentInstance,
+ inject,
+ onBeforeUnmount,
+ onMounted,
+ provide,
+ reactive,
+} from 'vue';
import omit from 'omit.js';
import PropTypes from '../_util/vue-types';
import Trigger from '../vc-trigger';
import KeyCode from '../_util/KeyCode';
-import { connect } from '../_util/store';
import SubPopupMenu from './SubPopupMenu';
import placements from './placements';
import BaseMixin from '../_util/BaseMixin';
-import { getComponent, filterEmpty, getSlot, splitAttrs, findDOMNode } from '../_util/props-util';
+import { getComponent, splitAttrs, findDOMNode, getSlot } from '../_util/props-util';
import { requestAnimationTimeout, cancelAnimationTimeout } from '../_util/requestAnimationTimeout';
-import { noop, getMenuIdFromSubMenuEventKey } from './util';
+import { noop, getMenuIdFromSubMenuEventKey, loopMenuItemRecursively } from './util';
import { getTransitionProps, Transition } from '../_util/transition';
-import { injectExtraPropsKey } from './FunctionProvider';
+import InjectExtraProps from './InjectExtraProps';
let guid = 0;
const popupPlacementMap = {
@@ -23,33 +31,27 @@ const popupPlacementMap = {
const updateDefaultActiveFirst = (store, eventKey, defaultActiveFirst) => {
const menuId = getMenuIdFromSubMenuEventKey(eventKey);
- const state = store.getState();
- store.setState({
- defaultActiveFirst: {
- ...state.defaultActiveFirst,
- [menuId]: defaultActiveFirst,
- },
- });
+ store.defaultActiveFirst[menuId] = defaultActiveFirst;
};
-
-const SubMenu = {
+let indexGuid = 0;
+const SubMenu = defineComponent({
name: 'SubMenu',
+ mixins: [BaseMixin],
inheritAttrs: false,
+ isSubMenu: true,
props: {
title: PropTypes.any,
- selectedKeys: PropTypes.array.def([]),
openKeys: PropTypes.array.def([]),
openChange: PropTypes.func.def(noop),
rootPrefixCls: PropTypes.string,
eventKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
multiple: PropTypes.looseBool,
- active: PropTypes.looseBool, // TODO: remove
isRootMenu: PropTypes.looseBool.def(false),
index: PropTypes.number,
triggerSubMenuAction: PropTypes.string,
popupClassName: PropTypes.string,
getPopupContainer: PropTypes.func,
- forceSubMenuRender: PropTypes.looseBool.def(true),
+ forceSubMenuRender: PropTypes.looseBool.def(false),
openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
disabled: PropTypes.looseBool,
subMenuOpenDelay: PropTypes.number.def(0.1),
@@ -58,8 +60,6 @@ const SubMenu = {
inlineIndent: PropTypes.number.def(24),
openTransitionName: PropTypes.string,
popupOffset: PropTypes.array,
- isOpen: PropTypes.looseBool,
- store: PropTypes.object,
mode: PropTypes.oneOf([
'horizontal',
'vertical',
@@ -73,20 +73,58 @@ const SubMenu = {
expandIcon: PropTypes.any,
subMenuKey: PropTypes.string,
theme: PropTypes.string,
+ parentUniKeys: PropTypes.array.def(() => []),
+ parentUniKey: PropTypes.string,
},
- mixins: [BaseMixin],
+
isSubMenu: true,
- setup() {
- return { parentMenu: inject('parentMenu', undefined) };
- },
- created() {
- provide('parentMenu', this);
+ setup(props) {
+ const uniKey = `sub_menu_${++indexGuid}`;
+ const store = inject('menuStore', () => ({}));
+ onMounted(() => {
+ store.addChildrenInfo(
+ uniKey,
+ computed(() => ({
+ parentUniKeys: props.parentUniKeys,
+ parentUniKey: props.parentUniKey,
+ eventKey: props.eventKey,
+ disabled: props.disabled,
+ })),
+ );
+ });
+ onBeforeUnmount(() => {
+ store.removeChildrenInfo(uniKey);
+ });
+ const isChildrenSelected = computed(() => {
+ return store.selectedParentUniKeys.indexOf(uniKey) !== -1;
+ });
+ const ins = getCurrentInstance();
+ const getEl = () => {
+ return ins.vnode.el;
+ };
+ provide(
+ 'parentMenu',
+ reactive({
+ isRootMenu: computed(() => props.isRootMenu),
+ getPopupContainer: props.getPopupContainer,
+ getEl,
+ }),
+ );
+ return {
+ parentMenu: inject('parentMenu', undefined),
+ store,
+ isChildrenSelected,
+ childrenUniKeys: [...props.parentUniKeys, uniKey],
+ uniKey,
+ isOpen: computed(() => store.openKeys.indexOf(props.eventKey) > -1),
+ active: computed(() => store.activeKey[props.subMenuKey] === props.eventKey),
+ };
},
data() {
const props = this.$props;
- const store = props.store;
+ const store = this.store;
const eventKey = props.eventKey;
- const defaultActiveFirst = store.getState().defaultActiveFirst;
+ const defaultActiveFirst = store.defaultActiveFirst;
let value = false;
if (defaultActiveFirst) {
@@ -98,32 +136,21 @@ const SubMenu = {
this.haveRendered = undefined;
this.haveOpened = undefined;
this.subMenuTitle = undefined;
- return {
- // defaultActiveFirst: false,
- childrenSelectedStatus: {},
- };
- },
- computed: {
- isChildrenSelected() {
- return Object.values(this.childrenSelectedStatus).find(status => status);
- },
+ return {};
},
mounted() {
this.$nextTick(() => {
this.handleUpdated();
});
- this.updateParentMenuSelectedStatus();
},
updated() {
this.$nextTick(() => {
this.handleUpdated();
});
- this.updateParentMenuSelectedStatus();
},
beforeUnmount() {
- this.updateParentMenuSelectedStatus(false);
const { eventKey } = this;
this.__emit('destroy', eventKey);
@@ -140,51 +167,40 @@ const SubMenu = {
}
},
methods: {
- updateParentMenuSelectedStatus(status = this.isChildrenSelected) {
- if (this.parentMenu && this.parentMenu.setChildrenSelectedStatus) {
- this.parentMenu.setChildrenSelectedStatus(this.eventKey, status);
- }
- },
- setChildrenSelectedStatus(key, status) {
- if (!status) {
- delete this.childrenSelectedStatus[key];
- } else {
- this.childrenSelectedStatus[key] = status;
- }
+ isChildrenSelected2() {
+ if (this.haveOpened) return this.isChildrenSelected;
+ const ret = { find: false };
+ loopMenuItemRecursively(getSlot(this), this.store.selectedKeys, ret);
+ return ret.find;
},
handleUpdated() {
- const { mode, parentMenu, manualRef } = this;
-
+ const { mode, manualRef } = this.$props;
// invoke customized ref to expose component to mixin
if (manualRef) {
manualRef(this);
}
-
- if (mode !== 'horizontal' || !parentMenu.isRootMenu || !this.isOpen) {
+ if (mode !== 'horizontal' || !this.parentMenu.isRootMenu || !this.isOpen) {
return;
}
-
this.minWidthTimeout = requestAnimationTimeout(() => this.adjustWidth(), 0);
},
onKeyDown(e) {
const keyCode = e.keyCode;
const menu = this.menuInstance;
- const { store, isOpen } = this.$props;
-
+ const { isOpen } = this;
if (keyCode === KeyCode.ENTER) {
this.onTitleClick(e);
- updateDefaultActiveFirst(store, this.eventKey, true);
+ updateDefaultActiveFirst(this.store, this.$props.eventKey, true);
return true;
}
-
if (keyCode === KeyCode.RIGHT) {
if (isOpen) {
menu.onKeyDown(e);
} else {
this.triggerOpenChange(true);
// need to update current menu's defaultActiveFirst value
- updateDefaultActiveFirst(store, this.eventKey, true);
+ updateDefaultActiveFirst(this.store, this.$props.eventKey, true);
}
return true;
}
@@ -213,8 +229,8 @@ const SubMenu = {
},
onMouseEnter(e) {
- const { eventKey: key, store } = this.$props;
- updateDefaultActiveFirst(store, key, false);
+ const { eventKey: key } = this.$props;
+ updateDefaultActiveFirst(this.store, key, false);
this.__emit('mouseenter', {
key,
domEvent: e,
@@ -222,7 +238,7 @@ const SubMenu = {
},
onMouseLeave(e) {
- const { eventKey } = this;
+ const { eventKey } = this.$props;
this.__emit('mouseleave', {
key: eventKey,
domEvent: e,
@@ -242,7 +258,7 @@ const SubMenu = {
},
onTitleMouseLeave(e) {
- const { eventKey } = this;
+ const { eventKey } = this.$props;
this.__emit('itemHover', {
key: eventKey,
hover: false,
@@ -254,7 +270,7 @@ const SubMenu = {
},
onTitleClick(e) {
- const { triggerSubMenuAction, eventKey, isOpen, store } = this.$props;
+ const { triggerSubMenuAction, eventKey } = this.$props;
this.__emit('titleClick', {
key: eventKey,
domEvent: e,
@@ -262,8 +278,8 @@ const SubMenu = {
if (triggerSubMenuAction === 'hover') {
return;
}
- this.triggerOpenChange(!isOpen, 'click');
- updateDefaultActiveFirst(store, eventKey, false);
+ this.triggerOpenChange(!this.isOpen, 'click');
+ updateDefaultActiveFirst(this.store, eventKey, false);
},
onSubMenuClick(info) {
@@ -301,22 +317,12 @@ const SubMenu = {
keyPath: (info.keyPath || []).concat(this.$props.eventKey),
};
},
-
- // triggerOpenChange (open, type) {
- // const key = this.$props.eventKey
- // this.__emit('openChange', {
- // key,
- // item: this,
- // trigger: type,
- // open,
- // })
- // },
triggerOpenChange(open, type) {
const key = this.$props.eventKey;
const openChange = () => {
this.__emit('openChange', {
key,
- item: this,
+ item: this.$props,
trigger: type,
open,
});
@@ -330,16 +336,6 @@ const SubMenu = {
openChange();
}
},
-
- // isChildrenSelected(children) {
- // const ret = { find: false };
- // loopMenuItemRecursively(children, this.$props.selectedKeys, ret);
- // return ret.find;
- // },
- // isOpen () {
- // return this.$props.openKeys.indexOf(this.$props.eventKey) !== -1
- // },
-
adjustWidth() {
/* istanbul ignore if */
if (!this.subMenuTitle || !this.menuInstance) {
@@ -356,16 +352,15 @@ const SubMenu = {
saveSubMenuTitle(subMenuTitle) {
this.subMenuTitle = subMenuTitle;
},
- renderChildren(children) {
+ renderChildren() {
const props = { ...this.$props, ...this.$attrs };
const subPopupMenuProps = {
mode: props.mode === 'horizontal' ? 'vertical' : props.mode,
- visible: props.isOpen,
+ visible: this.isOpen,
level: props.level + 1,
inlineIndent: props.inlineIndent,
focusable: false,
- selectedKeys: props.selectedKeys,
eventKey: `${props.eventKey}-menu-`,
openKeys: props.openKeys,
openTransitionName: props.openTransitionName,
@@ -375,20 +370,18 @@ const SubMenu = {
forceSubMenuRender: props.forceSubMenuRender,
triggerSubMenuAction: props.triggerSubMenuAction,
builtinPlacements: props.builtinPlacements,
- defaultActiveFirst: props.store.getState().defaultActiveFirst[
- getMenuIdFromSubMenuEventKey(props.eventKey)
- ],
multiple: props.multiple,
prefixCls: props.rootPrefixCls,
manualRef: this.saveMenuInstance,
itemIcon: getComponent(this, 'itemIcon'),
expandIcon: getComponent(this, 'expandIcon'),
- children,
onClick: this.onSubMenuClick,
onSelect: props.onSelect || noop,
onDeselect: props.onDeselect || noop,
onOpenChange: props.onOpenChange || noop,
id: this.internalMenuId,
+ parentUniKeys: this.childrenUniKeys,
+ parentUniKey: this.uniKey,
};
const haveRendered = this.haveRendered;
this.haveRendered = true;
@@ -424,7 +417,7 @@ const SubMenu = {
}
return (
-
+
);
},
@@ -433,19 +426,18 @@ const SubMenu = {
render() {
const props = { ...this.$props, ...this.$attrs };
const { onEvents } = splitAttrs(props);
- const isOpen = props.isOpen;
+ const isOpen = this.isOpen;
const prefixCls = this.getPrefixCls();
const isInlineMode = props.mode === 'inline';
- const childrenTemp = filterEmpty(getSlot(this));
- const children = this.renderChildren(childrenTemp);
+ const children = this.renderChildren();
const className = {
[prefixCls]: true,
[`${prefixCls}-${props.mode}`]: true,
[props.class]: !!props.class,
[this.getOpenClassName()]: isOpen,
- [this.getActiveClassName()]: props.active || (isOpen && !isInlineMode),
+ [this.getActiveClassName()]: this.active || (isOpen && !isInlineMode),
[this.getDisabledClassName()]: props.disabled,
- [this.getSelectedClassName()]: this.isChildrenSelected,
+ [this.getSelectedClassName()]: this.isChildrenSelected || this.isChildrenSelected2(),
};
if (!this.internalMenuId) {
@@ -511,7 +503,6 @@ const SubMenu = {
{icon || }
);
-
const getPopupContainer = this.parentMenu.isRootMenu
? this.parentMenu.getPopupContainer
: triggerNode => triggerNode.parentNode;
@@ -555,16 +546,6 @@ const SubMenu = {
);
},
-};
-
-const connected = connect(({ openKeys, activeKey, selectedKeys }, { eventKey, subMenuKey }) => {
- return {
- isOpen: openKeys.indexOf(eventKey) > -1,
- active: activeKey[subMenuKey] === eventKey,
- selectedKeys,
- };
-}, injectExtraPropsKey)(SubMenu);
-
-connected.isSubMenu = true;
+});
-export default connected;
+export default InjectExtraProps(SubMenu);
diff --git a/components/vc-menu/SubPopupMenu.jsx b/components/vc-menu/SubPopupMenu.jsx
index 864c6d046f..12f96927ea 100644
--- a/components/vc-menu/SubPopupMenu.jsx
+++ b/components/vc-menu/SubPopupMenu.jsx
@@ -1,19 +1,19 @@
import { Comment, inject } from 'vue';
import PropTypes from '../_util/vue-types';
-import { connect } from '../_util/store';
import BaseMixin from '../_util/BaseMixin';
import KeyCode from '../_util/KeyCode';
import classNames from '../_util/classNames';
-import { getKeyFromChildrenIndex, loopMenuItem, noop, isMobileDevice, menuAllProps } from './util';
+import { getKeyFromChildrenIndex, noop, isMobileDevice, menuAllProps } from './util';
import DOMWrap from './DOMWrap';
import {
initDefaultProps,
getOptionProps,
getComponent,
splitAttrs,
- getPropsData,
+ getSlot,
} from '../_util/props-util';
import FunctionProvider from './FunctionProvider';
+// import { getActiveKey } from '../vc-tabs/src/utils';
function allDisabled(arr) {
if (!arr.length) {
return true;
@@ -24,13 +24,7 @@ function allDisabled(arr) {
}
function updateActiveKey(store, menuId, activeKey) {
- const state = store.getState();
- store.setState({
- activeKey: {
- ...state.activeKey,
- [menuId]: activeKey,
- },
- });
+ store.activeKey[menuId] = activeKey;
}
function getEventKey(props) {
@@ -44,34 +38,34 @@ export function saveRef(key, c) {
this.instanceArray[index] = c;
}
}
-export function getActiveKey(props, originalActiveKey) {
- let activeKey = originalActiveKey;
- const { eventKey, defaultActiveFirst, children } = props;
- if (activeKey !== undefined && activeKey !== null) {
- let found;
- loopMenuItem(children, (c, i) => {
- const propsData = getPropsData(c);
- if (c && !propsData.disabled && activeKey === getKeyFromChildrenIndex(c, eventKey, i)) {
- found = true;
- }
- });
- if (found) {
- return activeKey;
- }
- }
- activeKey = null;
- if (defaultActiveFirst) {
- loopMenuItem(children, (c, i) => {
- const propsData = getPropsData(c);
- const noActiveKey = activeKey === null || activeKey === undefined;
- if (noActiveKey && c && !propsData.disabled) {
- activeKey = getKeyFromChildrenIndex(c, eventKey, i);
- }
- });
- return activeKey;
- }
- return activeKey;
-}
+// export function getActiveKey(props, originalActiveKey) {
+// let activeKey = originalActiveKey;
+// const { eventKey, defaultActiveFirst, children } = props;
+// if (activeKey !== undefined && activeKey !== null) {
+// let found;
+// loopMenuItem(children, (c, i) => {
+// const propsData = getPropsData(c);
+// if (c && !propsData.disabled && activeKey === getKeyFromChildrenIndex(c, eventKey, i)) {
+// found = true;
+// }
+// });
+// if (found) {
+// return activeKey;
+// }
+// }
+// activeKey = null;
+// if (defaultActiveFirst) {
+// loopMenuItem(children, (c, i) => {
+// const propsData = getPropsData(c);
+// const noActiveKey = activeKey === null || activeKey === undefined;
+// if (noActiveKey && c && !propsData.disabled) {
+// activeKey = getKeyFromChildrenIndex(c, eventKey, i);
+// }
+// });
+// return activeKey;
+// }
+// return activeKey;
+// }
const SubPopupMenu = {
name: 'SubPopupMenu',
@@ -89,14 +83,12 @@ const SubPopupMenu = {
openKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
visible: PropTypes.looseBool,
eventKey: PropTypes.string,
- store: PropTypes.object,
// adding in refactor
focusable: PropTypes.looseBool,
multiple: PropTypes.looseBool,
defaultActiveFirst: PropTypes.looseBool,
activeKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
- selectedKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
defaultSelectedKeys: PropTypes.arrayOf(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
),
@@ -116,7 +108,9 @@ const SubPopupMenu = {
expandIcon: PropTypes.any,
overflowedIndicator: PropTypes.any,
children: PropTypes.any.def([]),
- forceSubMenuRender: PropTypes.looseBool.def(true),
+ forceSubMenuRender: PropTypes.looseBool.def(false),
+ parentUniKeys: PropTypes.array.def(() => []),
+ parentUniKey: PropTypes.string,
},
{
prefixCls: 'rc-menu',
@@ -131,17 +125,13 @@ const SubPopupMenu = {
mixins: [BaseMixin],
setup() {
- return { parentMenu: inject('parentMenu', undefined) };
+ const store = inject('menuStore', () => ({}));
+ return { store };
},
created() {
const props = getOptionProps(this);
this.prevProps = { ...props };
- props.store.setState({
- activeKey: {
- ...props.store.getState().activeKey,
- [props.eventKey]: getActiveKey(props, props.activeKey),
- },
- });
+ this.store.activeKey[props.eventKey] = this.store.getActiveKey(props.activeKey);
this.instanceArray = [];
},
mounted() {
@@ -154,16 +144,16 @@ const SubPopupMenu = {
const props = getOptionProps(this);
const prevProps = this.prevProps;
const originalActiveKey =
- 'activeKey' in props ? props.activeKey : props.store.getState().activeKey[getEventKey(props)];
- const activeKey = getActiveKey(props, originalActiveKey);
+ 'activeKey' in props ? props.activeKey : this.store.activeKey[getEventKey(props)];
+ const activeKey = this.store.getActiveKey(originalActiveKey);
if (activeKey !== originalActiveKey) {
- updateActiveKey(props.store, getEventKey(props), activeKey);
+ updateActiveKey(this.store, getEventKey(props), activeKey);
} else if ('activeKey' in prevProps) {
// If prev activeKey is not same as current activeKey,
// we should set it.
- const prevActiveKey = getActiveKey(prevProps, prevProps.activeKey);
+ const prevActiveKey = this.store.getActiveKey(prevProps.activeKey);
if (activeKey !== prevActiveKey) {
- updateActiveKey(props.store, getEventKey(props), activeKey);
+ updateActiveKey(this.store, getEventKey(props), activeKey);
}
}
this.prevProps = { ...props };
@@ -187,7 +177,7 @@ const SubPopupMenu = {
}
if (activeItem) {
e.preventDefault();
- updateActiveKey(this.$props.store, getEventKey(this.$props), activeItem.eventKey);
+ updateActiveKey(this.store, getEventKey(this.$props), activeItem.eventKey);
if (typeof callback === 'function') {
callback(activeItem);
@@ -200,7 +190,7 @@ const SubPopupMenu = {
onItemHover(e) {
const { key, hover } = e;
- updateActiveKey(this.$props.store, getEventKey(this.$props), hover ? key : null);
+ updateActiveKey(this.store, getEventKey(this.$props), hover ? key : null);
},
onDeselect(selectInfo) {
@@ -233,7 +223,7 @@ const SubPopupMenu = {
step(direction) {
let children = this.getFlatInstanceArray();
- const activeKey = this.$props.store.getState().activeKey[getEventKey(this.$props)];
+ const activeKey = this.store.activeKey[getEventKey(this.$props)];
const len = children.length;
if (!len) {
return null;
@@ -278,7 +268,7 @@ const SubPopupMenu = {
if (child.type === Comment) {
return child;
}
- const state = this.$props.store.getState();
+ const state = this.store;
const props = this.$props;
const key = getKeyFromChildrenIndex(child, props.eventKey, i);
const childProps = child.props || {}; // child.props 包含事件
@@ -317,6 +307,8 @@ const SubPopupMenu = {
onDeselect: this.onDeselect,
// destroy: this.onDestroy,
onSelect: this.onSelect,
+ parentUniKeys: this.parentUniKeys,
+ parentUniKey: this.parentUniKey,
};
if (props.forceSubMenuRender !== undefined) {
newChildProps.forceSubMenuRender = props.forceSubMenuRender;
@@ -325,14 +317,14 @@ const SubPopupMenu = {
if (props.mode === 'inline' || isMobileDevice()) {
newChildProps.triggerSubMenuAction = 'click';
}
- return {child};
+ return {child};
},
renderMenuItem(c, i, subMenuKey) {
if (!c) {
return null;
}
- const state = this.$props.store.getState();
+ const state = this.store;
const extraProps = {
openKeys: state.openKeys,
selectedKeys: state.selectedKeys,
@@ -384,11 +376,11 @@ const SubPopupMenu = {
// ESLint is not smart enough to know that the type of `children` was checked.
/* eslint-disable */
- {props.children.map((c, i) => this.renderMenuItem(c, i, eventKey || '0-menu-'))}
+ {getSlot(this).map((c, i) => this.renderMenuItem(c, i, eventKey || '0-menu-'))}
/*eslint -enable */
);
},
};
-export default connect(undefined)(SubPopupMenu);
+export default SubPopupMenu;
diff --git a/components/vc-menu/commonPropsType.js b/components/vc-menu/commonPropsType.js
index 29d8de013d..7c6afa174a 100644
--- a/components/vc-menu/commonPropsType.js
+++ b/components/vc-menu/commonPropsType.js
@@ -3,7 +3,6 @@ export default {
prefixCls: PropTypes.string.def('rc-menu'),
focusable: PropTypes.looseBool.def(true),
multiple: PropTypes.looseBool,
- defaultActiveFirst: PropTypes.looseBool,
visible: PropTypes.looseBool.def(true),
activeKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
selectedKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
@@ -30,7 +29,7 @@ export default {
theme: PropTypes.oneOf(['light', 'dark']).def('light'),
getPopupContainer: PropTypes.func,
openTransitionName: PropTypes.string,
- forceSubMenuRender: PropTypes.looseBool.def(true),
+ forceSubMenuRender: PropTypes.looseBool.def(false),
selectable: PropTypes.looseBool,
isRootMenu: PropTypes.looseBool.def(true),
builtinPlacements: PropTypes.object.def(() => ({})),
@@ -40,5 +39,4 @@ export default {
onClick: PropTypes.func,
onSelect: PropTypes.func,
onDeselect: PropTypes.func,
- children: PropTypes.VNodeChild,
};
diff --git a/components/vc-menu/util.js b/components/vc-menu/util.js
index e460618cc9..b292acd072 100644
--- a/components/vc-menu/util.js
+++ b/components/vc-menu/util.js
@@ -12,21 +12,21 @@ export function getMenuIdFromSubMenuEventKey(eventKey) {
return `${eventKey}-menu-`;
}
-export function loopMenuItem(children, cb) {
- let index = -1;
- children.forEach(c => {
- index++;
- if (c && c.type && c.type.isMenuItemGroup) {
- c.children.default &&
- c.children.default().forEach(c2 => {
- index++;
- cb(c2, index);
- });
- } else {
- cb(c, index);
- }
- });
-}
+// export function loopMenuItem(children, cb) {
+// let index = -1;
+// children.forEach(c => {
+// index++;
+// if (c && c.type && c.type.isMenuItemGroup) {
+// c.children.default &&
+// c.children.default().forEach(c2 => {
+// index++;
+// cb(c2, index);
+// });
+// } else {
+// cb(c, index);
+// }
+// });
+// }
export function loopMenuItemRecursively(children, keys, ret) {
if (!children || ret.find) {
@@ -113,6 +113,8 @@ export const menuAllProps = [
'slots',
'ref',
'isRootMenu',
+ 'parentUniKeys',
+ 'parentUniKey',
];
// ref: https://github.com/ant-design/ant-design/issues/14007
diff --git a/examples/App.vue b/examples/App.vue
index b8dfa18c9d..2a473db443 100644
--- a/examples/App.vue
+++ b/examples/App.vue
@@ -1,39 +1,30 @@
-
-
-
+
+ e.preventDefault()">
+ Cascading menu
+
+
+
+ 1st menu item
+ 2nd menu item
+
+ 3rd menu item
+ 4th menu item
+
+
+ 5d menu item
+ 6th menu item
+
+
+
+