refactor: menu
parent
f3db7548b5
commit
24efefe16d
|
@ -1,4 +1,4 @@
|
|||
import { computed, defineComponent, reactive, ref, watch } from '@vue/runtime-core';
|
||||
import { computed, defineComponent, ref, watch } from '@vue/runtime-core';
|
||||
import Transition from 'ant-design-vue/es/_util/transition';
|
||||
import { useInjectMenu, MenuContextProvider } from './hooks/useMenuContext';
|
||||
import { MenuMode } from './interface';
|
||||
|
@ -14,7 +14,7 @@ export default defineComponent({
|
|||
},
|
||||
setup(props, { slots }) {
|
||||
const fixedMode: MenuMode = 'inline';
|
||||
const { prefixCls, forceSubMenuRender, motion, mode, defaultMotions } = useInjectMenu();
|
||||
const { forceSubMenuRender, motion, mode, defaultMotions } = useInjectMenu();
|
||||
const sameModeRef = computed(() => mode.value === fixedMode);
|
||||
const destroy = ref(!sameModeRef.value);
|
||||
|
||||
|
|
|
@ -14,7 +14,14 @@ import {
|
|||
import shallowEqual from '../../_util/shallowequal';
|
||||
import useProvideMenu, { StoreMenuInfo, useProvideFirstLevel } from './hooks/useMenuContext';
|
||||
import useConfigInject from '../../_util/hooks/useConfigInject';
|
||||
import { MenuTheme, MenuMode, BuiltinPlacements, TriggerSubMenuAction } from './interface';
|
||||
import {
|
||||
MenuTheme,
|
||||
MenuMode,
|
||||
BuiltinPlacements,
|
||||
TriggerSubMenuAction,
|
||||
MenuInfo,
|
||||
SelectInfo,
|
||||
} from './interface';
|
||||
import devWarning from 'ant-design-vue/es/vc-util/devWarning';
|
||||
import { collapseMotion, CSSMotionProps } from 'ant-design-vue/es/_util/transition';
|
||||
|
||||
|
@ -24,6 +31,9 @@ export const menuProps = {
|
|||
inlineCollapsed: Boolean,
|
||||
overflowDisabled: Boolean,
|
||||
openKeys: Array,
|
||||
selectedKeys: Array,
|
||||
selectable: Boolean,
|
||||
multiple: Boolean,
|
||||
|
||||
motion: Object as PropType<CSSMotionProps>,
|
||||
|
||||
|
@ -46,7 +56,7 @@ export type MenuProps = Partial<ExtractPropTypes<typeof menuProps>>;
|
|||
export default defineComponent({
|
||||
name: 'AMenu',
|
||||
props: menuProps,
|
||||
emits: ['update:openKeys', 'openChange'],
|
||||
emits: ['update:openKeys', 'openChange', 'select', 'deselect', 'update:selectedKeys'],
|
||||
setup(props, { slots, emit }) {
|
||||
const { prefixCls, direction } = useConfigInject('menu', props);
|
||||
const store = reactive<Record<string, StoreMenuInfo>>({});
|
||||
|
@ -81,7 +91,48 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
const activeKeys = ref([]);
|
||||
const selectedKeys = ref([]);
|
||||
const mergedSelectedKeys = ref([]);
|
||||
|
||||
watch(
|
||||
() => props.selectedKeys,
|
||||
(selectedKeys = mergedSelectedKeys.value) => {
|
||||
mergedSelectedKeys.value = selectedKeys;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// >>>>> Trigger select
|
||||
const triggerSelection = (info: MenuInfo) => {
|
||||
if (!props.selectable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert or Remove
|
||||
const { key: targetKey } = info;
|
||||
const exist = mergedSelectedKeys.value.includes(targetKey);
|
||||
let newSelectedKeys: Key[];
|
||||
|
||||
if (exist) {
|
||||
newSelectedKeys = mergedSelectedKeys.value.filter(key => key !== targetKey);
|
||||
} else if (props.multiple) {
|
||||
newSelectedKeys = [...mergedSelectedKeys.value, targetKey];
|
||||
} else {
|
||||
newSelectedKeys = [targetKey];
|
||||
}
|
||||
|
||||
mergedSelectedKeys.value = newSelectedKeys;
|
||||
// Trigger event
|
||||
const selectInfo: SelectInfo = {
|
||||
...info,
|
||||
selectedKeys: newSelectedKeys,
|
||||
};
|
||||
|
||||
if (exist) {
|
||||
emit('deselect', selectInfo);
|
||||
} else {
|
||||
emit('select', selectInfo);
|
||||
}
|
||||
};
|
||||
|
||||
const mergedOpenKeys = ref([]);
|
||||
|
||||
|
@ -201,7 +252,7 @@ export default defineComponent({
|
|||
prefixCls,
|
||||
activeKeys,
|
||||
openKeys: mergedOpenKeys,
|
||||
selectedKeys,
|
||||
selectedKeys: mergedSelectedKeys,
|
||||
changeActiveKeys,
|
||||
disabled,
|
||||
rtl: isRtl,
|
||||
|
@ -219,6 +270,7 @@ export default defineComponent({
|
|||
motion: computed(() => (isMounted.value ? props.motion : null)),
|
||||
overflowDisabled: computed(() => props.overflowDisabled),
|
||||
onOpenChange: onInternalOpenChange,
|
||||
onItemClick: triggerSelection,
|
||||
registerMenuInfo,
|
||||
unRegisterMenuInfo,
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@ import { useInjectKeyPath } from './hooks/useKeyPath';
|
|||
import { useInjectFirstLevel, useInjectMenu } from './hooks/useMenuContext';
|
||||
import { cloneElement } from '../../_util/vnode';
|
||||
import Tooltip from '../../tooltip';
|
||||
import { MenuInfo } from './interface';
|
||||
|
||||
let indexGuid = 0;
|
||||
|
||||
|
@ -17,7 +18,7 @@ export default defineComponent({
|
|||
title: { type: [String, Boolean] },
|
||||
icon: PropTypes.VNodeChild,
|
||||
},
|
||||
emits: ['mouseenter', 'mouseleave'],
|
||||
emits: ['mouseenter', 'mouseleave', 'click'],
|
||||
slots: ['icon'],
|
||||
inheritAttrs: false,
|
||||
setup(props, { slots, emit, attrs }) {
|
||||
|
@ -34,6 +35,7 @@ export default defineComponent({
|
|||
rtl,
|
||||
inlineCollapsed,
|
||||
siderCollapsed,
|
||||
onItemClick,
|
||||
} = useInjectMenu();
|
||||
const firstLevel = useInjectFirstLevel();
|
||||
const isActive = ref(false);
|
||||
|
@ -56,6 +58,27 @@ export default defineComponent({
|
|||
[`${itemCls}-disabled`]: mergedDisabled.value,
|
||||
};
|
||||
});
|
||||
|
||||
const getEventInfo = (e: MouseEvent): MenuInfo => {
|
||||
return {
|
||||
key: key,
|
||||
eventKey: eventKey,
|
||||
eventKeyPath: [...parentEventKeys.value, key],
|
||||
domEvent: e,
|
||||
};
|
||||
};
|
||||
|
||||
// ============================ Events ============================
|
||||
const onInternalClick = (e: MouseEvent) => {
|
||||
if (mergedDisabled.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const info = getEventInfo(e);
|
||||
emit('click', e);
|
||||
onItemClick(info);
|
||||
};
|
||||
|
||||
const onMouseEnter = (event: MouseEvent) => {
|
||||
if (!mergedDisabled.value) {
|
||||
changeActiveKeys([...parentEventKeys.value, key]);
|
||||
|
@ -135,6 +158,7 @@ export default defineComponent({
|
|||
{...optionRoleProps}
|
||||
onMouseenter={onMouseEnter}
|
||||
onMouseleave={onMouseLeave}
|
||||
onClick={onInternalClick}
|
||||
title={typeof title === 'string' ? title : undefined}
|
||||
>
|
||||
{cloneElement(icon, {
|
||||
|
|
|
@ -9,7 +9,13 @@ import {
|
|||
Ref,
|
||||
UnwrapRef,
|
||||
} from 'vue';
|
||||
import { BuiltinPlacements, MenuMode, MenuTheme, TriggerSubMenuAction } from '../interface';
|
||||
import {
|
||||
BuiltinPlacements,
|
||||
MenuClickEventHandler,
|
||||
MenuMode,
|
||||
MenuTheme,
|
||||
TriggerSubMenuAction,
|
||||
} from '../interface';
|
||||
import { CSSMotionProps } from '../../../_util/transition';
|
||||
|
||||
export interface StoreMenuInfo {
|
||||
|
@ -77,7 +83,7 @@ export interface MenuContextProps {
|
|||
// expandIcon?: RenderIconType;
|
||||
|
||||
// // Function
|
||||
// onItemClick: MenuClickEventHandler;
|
||||
onItemClick: MenuClickEventHandler;
|
||||
onOpenChange: (key: Key, open: boolean) => void;
|
||||
getPopupContainer: ComputedRef<(node: HTMLElement) => HTMLElement>;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { Key } from 'ant-design-vue/es/_util/type';
|
||||
|
||||
export type MenuTheme = 'light' | 'dark';
|
||||
|
||||
// ========================== Basic ==========================
|
||||
|
@ -17,22 +19,24 @@ export interface RenderIconInfo {
|
|||
export type RenderIconType = (props: RenderIconInfo) => any;
|
||||
|
||||
export interface MenuInfo {
|
||||
key: string;
|
||||
keyPath: string[];
|
||||
key: Key;
|
||||
eventKey: string;
|
||||
keyPath?: string[];
|
||||
eventKeyPath: Key[];
|
||||
domEvent: MouseEvent | KeyboardEvent;
|
||||
}
|
||||
|
||||
export interface MenuTitleInfo {
|
||||
key: string;
|
||||
key: Key;
|
||||
domEvent: MouseEvent | KeyboardEvent;
|
||||
}
|
||||
|
||||
// ========================== Hover ==========================
|
||||
export type MenuHoverEventHandler = (info: { key: string; domEvent: MouseEvent }) => void;
|
||||
export type MenuHoverEventHandler = (info: { key: Key; domEvent: MouseEvent }) => void;
|
||||
|
||||
// ======================== Selection ========================
|
||||
export interface SelectInfo extends MenuInfo {
|
||||
selectedKeys: string[];
|
||||
selectedKeys: Key[];
|
||||
}
|
||||
|
||||
export type SelectEventHandler = (info: SelectInfo) => void;
|
||||
|
|
2
v2-doc
2
v2-doc
|
@ -1 +1 @@
|
|||
Subproject commit a7013ae87f69dcbcf547f4b023255b8a7a775557
|
||||
Subproject commit d197053285b81e77718621c0b5b94cb3b21831a2
|
Loading…
Reference in New Issue