Commit dfab7a66 authored by Sendya's avatar Sendya

feat: test menu

parent e0039d25
...@@ -2,7 +2,9 @@ import { createApp, onMounted, reactive, watch, watchEffect } from 'vue'; ...@@ -2,7 +2,9 @@ import { createApp, onMounted, reactive, watch, watchEffect } from 'vue';
import { menus } from './menus'; import { menus } from './menus';
import { MenuTheme } from '../src/typings'; import { MenuTheme } from '../src/typings';
import { Card, Space, Button, Switch } from 'ant-design-vue'; import { Card, Space, Button, Switch } from 'ant-design-vue';
import BaseMenu, { useMenuState, MenuMode } from '../src/SiderMenu/BaseMenu'; import { useMenu } from '../src/hooks/useMenu';
import { RouterLink } from './mock-router';
import { default as BaseMenu, MenuMode } from '../src/SiderMenu/BaseMenu';
import * as Icon from '@ant-design/icons-vue'; import * as Icon from '@ant-design/icons-vue';
import 'ant-design-vue/dist/antd.less'; import 'ant-design-vue/dist/antd.less';
...@@ -15,10 +17,10 @@ const BaseMenuDemo = { ...@@ -15,10 +17,10 @@ const BaseMenuDemo = {
themeChecked: true, themeChecked: true,
modeChecked: true, modeChecked: true,
}) })
const [menuState] = useMenuState({ const [menuState] = useMenu({
collapsed: false, collapsed: false,
openKeys: ['/dashboard'] as string[], openKeys: ['/dashboard'],
selectedKeys: ['/dashboard/monitor'] as string[], selectedKeys: ['/dashboard/monitor'],
}) })
onMounted(() => { onMounted(() => {
...@@ -89,4 +91,4 @@ Object.keys(Icon) ...@@ -89,4 +91,4 @@ Object.keys(Icon)
app.component(Icon[k].displayName, Icon[k]) app.component(Icon[k].displayName, Icon[k])
}) })
app.mount('#__vue-content>div'); app.use(RouterLink).mount('#__vue-content>div');
...@@ -4,7 +4,6 @@ import { RouterLink } from './mock-router'; ...@@ -4,7 +4,6 @@ import { RouterLink } from './mock-router';
import { Button, Avatar, message } from 'ant-design-vue'; import { Button, Avatar, message } from 'ant-design-vue';
import { default as ProLayout } from '../src/'; import { default as ProLayout } from '../src/';
import { menus } from './menus'; import { menus } from './menus';
import { useMenuState } from '../src/SiderMenu/BaseMenu';
import * as Icon from '@ant-design/icons-vue'; import * as Icon from '@ant-design/icons-vue';
import { createRouteContext } from '../src/RouteContext'; import { createRouteContext } from '../src/RouteContext';
......
...@@ -5,31 +5,23 @@ import './side-menu.less'; ...@@ -5,31 +5,23 @@ import './side-menu.less';
import { Layout, Input, Space, Switch, message } from 'ant-design-vue'; import { Layout, Input, Space, Switch, message } from 'ant-design-vue';
import { menus } from './menus'; import { menus } from './menus';
import { default as SiderMenuWrapper } from '../src/SiderMenu'; import { default as SiderMenuWrapper } from '../src/SiderMenu';
import { useMenuState } from '../src/SiderMenu/BaseMenu'; import { useMenu } from '../src/hooks/useMenu';
import * as Icon from '@ant-design/icons-vue'; import * as Icon from '@ant-design/icons-vue';
import { MenuTheme } from '../src/typings'; import { MenuTheme } from '../src/typings';
const DemoComponent = { const DemoComponent = {
setup() { setup() {
const [menuState] = useMenuState({ const [menuState] = useMenu({
collapsed: false, collapsed: false,
openKeys: [''], openKeys: [''],
selectedKeys: ['/welcome'], selectedKeys: ['/welcome'],
}); });
const state = reactive({ const state = reactive({
theme: 'dark', theme: 'light',
}) });
const handleCollapse = (collapsed: boolean) => { const handleCollapse = (collapsed: boolean) => {
menuState.collapsed = collapsed; menuState.collapsed = collapsed;
}; }
const handleOpenChange = (openKeys: string[]) => {
menuState.openKeys = openKeys;
};
const handleSelect = (selectedKeys: string[]) => {
menuState.selectedKeys = selectedKeys;
};
return () => ( return () => (
<div class="components"> <div class="components">
<h2># SideMenu</h2> <h2># SideMenu</h2>
...@@ -48,10 +40,8 @@ const DemoComponent = { ...@@ -48,10 +40,8 @@ const DemoComponent = {
isMobile={false} isMobile={false}
collapsed={menuState.collapsed} collapsed={menuState.collapsed}
menuData={menus} menuData={menus}
openKeys={menuState.openKeys} // openKeys={menuState.openKeys}
selectedKeys={menuState.selectedKeys} // selectedKeys={menuState.selectedKeys}
onOpenChange={handleOpenChange}
onSelect={handleSelect}
onCollapse={handleCollapse} onCollapse={handleCollapse}
matchMenuKeys={[]} matchMenuKeys={[]}
contentWidth={'Fixed'} contentWidth={'Fixed'}
......
import { import {
defineComponent, defineComponent,
resolveComponent, resolveComponent,
ref,
reactive,
computed, computed,
Ref,
watch,
ComputedRef, ComputedRef,
VNodeChild, VNodeChild,
VNode, VNode,
WatchStopHandle,
PropType, PropType,
isVNode, isVNode,
toRefs, toRefs,
} from 'vue'; } from 'vue';
import { createFromIconfontCN } from '@ant-design/icons-vue'; import { createFromIconfontCN } from '@ant-design/icons-vue';
import 'ant-design-vue/es/menu/style'; import 'ant-design-vue/es/menu/style';
import Menu from 'ant-design-vue/es/menu'; import Menu, { MenuProps } from 'ant-design-vue/es/menu';
import defaultSettings, { PureSettings } from '../defaultSettings'; import defaultSettings, { PureSettings } from '../defaultSettings';
import { isImg, isUrl } from '../utils'; import { isImg, isUrl } from '../utils';
import { MenuMode, SelectInfo, OpenEventHandler } from './typings'; import { MenuMode, SelectInfo, OpenEventHandler } from './typings';
import { MenuDataItem, MenuTheme, FormatMessage, WithFalse } from '../typings'; import { MenuDataItem, MenuTheme, FormatMessage, WithFalse } from '../typings';
import { PrivateSiderMenuProps } from './SiderMenu'; import { PrivateSiderMenuProps } from './SiderMenu';
import './index.less'; import './index.less';
import { useMenuState } from '../hooks/useMenu';
export { MenuMode, SelectInfo, OpenEventHandler }; export { MenuMode, SelectInfo, OpenEventHandler };
export interface MenuState {
collapsed?: boolean | false;
selectedKeys?: string[];
openKeys?: string[];
}
interface MenuStated {
collapsed: boolean;
selectedKeys: string[];
openKeys: string[];
}
export type MenuStateWatched = [MenuStated, WatchStopHandle];
export function useMenuState({
collapsed = false,
openKeys = [] as string[],
selectedKeys = [] as string[],
}: MenuState): MenuStateWatched {
const state = reactive<MenuStated>({
collapsed,
selectedKeys,
openKeys,
});
const cachedOpenKeys: Ref<string[]> = ref([] as string[]);
const watchRef = watch(
() => state.collapsed,
collapsed => {
if (collapsed) {
cachedOpenKeys.value = state.openKeys.concat();
state.openKeys = [];
} else {
state.openKeys = cachedOpenKeys.value.concat();
}
},
);
return [state, watchRef];
}
export function useRootSubmenuKeys(menus: MenuDataItem[]): ComputedRef<string[]> { export function useRootSubmenuKeys(menus: MenuDataItem[]): ComputedRef<string[]> {
return computed(() => menus.map(it => it.path)); return computed(() => menus.map(it => it.path));
} }
// ts typo // ts typo
export interface BaseMenuProps extends Partial<PureSettings> { export interface BaseMenuProps extends Partial<PureSettings>, PrivateSiderMenuProps {
prefixCls?: string; prefixCls?: string;
collapsed?: boolean; collapsed?: boolean;
splitMenus?: boolean; splitMenus?: boolean;
...@@ -101,16 +56,16 @@ export const VueBaseMenuProps = { ...@@ -101,16 +56,16 @@ export const VueBaseMenuProps = {
default: 'dark', default: 'dark',
}, },
collapsed: { collapsed: {
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean | undefined>,
default: false, default: false,
}, },
openKeys: { openKeys: {
type: Array as PropType<WithFalse<string[]>>, type: Array as PropType<WithFalse<string[]>>,
required: true, default: undefined,
}, },
selectedKeys: { selectedKeys: {
type: Array as PropType<WithFalse<string[]>>, type: Array as PropType<WithFalse<string[]>>,
required: true, default: undefined,
}, },
}; };
...@@ -212,8 +167,10 @@ export default defineComponent({ ...@@ -212,8 +167,10 @@ export default defineComponent({
emits: ['update:openKeys', 'update:selectedKeys'], emits: ['update:openKeys', 'update:selectedKeys'],
setup(props, { emit }) { setup(props, { emit }) {
const { mode, i18n } = toRefs(props); const { mode, i18n } = toRefs(props);
const state = useMenuState();
const isInline = computed(() => mode.value === 'inline'); const isInline = computed(() => mode.value === 'inline');
const handleOpenChange: OpenEventHandler = (openKeys): void => { const handleOpenChange: OpenEventHandler = (openKeys: string[]): void => {
state?.setOpenKeys(openKeys);
emit('update:openKeys', openKeys); emit('update:openKeys', openKeys);
}; };
const handleSelect = (params: { const handleSelect = (params: {
...@@ -223,6 +180,7 @@ export default defineComponent({ ...@@ -223,6 +180,7 @@ export default defineComponent({
domEvent: MouseEvent; domEvent: MouseEvent;
selectedKeys: string[]; selectedKeys: string[];
}): void => { }): void => {
state?.setSelectedKeys(params.selectedKeys);
emit('update:selectedKeys', params.selectedKeys); emit('update:selectedKeys', params.selectedKeys);
}; };
return () => ( return () => (
...@@ -232,8 +190,8 @@ export default defineComponent({ ...@@ -232,8 +190,8 @@ export default defineComponent({
inlineIndent={16} inlineIndent={16}
mode={props.mode} mode={props.mode}
theme={props.theme as 'dark' | 'light'} theme={props.theme as 'dark' | 'light'}
openKeys={props.openKeys || []} openKeys={props.openKeys || state?.openKeys.value || []}
selectedKeys={props.selectedKeys || []} selectedKeys={props.selectedKeys || state?.selectedKeys.value || []}
onOpenChange={handleOpenChange} onOpenChange={handleOpenChange}
onSelect={handleSelect} onSelect={handleSelect}
> >
......
...@@ -121,7 +121,7 @@ const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) = ...@@ -121,7 +121,7 @@ const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) =
const extraDom = menuExtraRender && menuExtraRender(props); const extraDom = menuExtraRender && menuExtraRender(props);
const defaultMenuDom = ( const defaultMenuDom = (
<BaseMenu <BaseMenu
theme={props.navTheme === 'realDark' ? 'dark' : props.navTheme} theme={navTheme === 'realDark' ? 'dark' : navTheme}
mode="inline" mode="inline"
menuData={context.menuData} menuData={context.menuData}
collapsed={props.collapsed} collapsed={props.collapsed}
...@@ -157,6 +157,7 @@ const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) = ...@@ -157,6 +157,7 @@ const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) =
)} )}
<Sider <Sider
class={classNames.value} class={classNames.value}
theme={navTheme === 'realDark' ? 'dark' : navTheme}
width={siderWidth} width={siderWidth}
breakpoint={breakpoint || undefined} breakpoint={breakpoint || undefined}
collapsed={collapsed} collapsed={collapsed}
......
import {
ref,
reactive,
watch,
provide,
inject,
InjectionKey,
Ref,
WatchStopHandle,
toRefs,
ToRefs,
} from 'vue';
export interface MenuState {
collapsed?: boolean | false;
selectedKeys?: string[];
openKeys?: string[];
}
export type MenuHandles = {
setCollapsed: (collapsed: boolean) => void;
setSelectedKeys: (selectedKeys: string[]) => void;
setOpenKeys: (openKeys: string[]) => void;
};
export type MenuStated = Required<MenuState>;
export type MenuStateWatched = [MenuStated, MenuHandles, WatchStopHandle];
export const MenuStateKey: InjectionKey<ToRefs<MenuStated> & MenuHandles> = Symbol('menu-state');
export function useMenu({ collapsed = false, openKeys = [], selectedKeys = [] }: MenuState) {
const cacheKeys: Ref<string[]> = ref([] as string[]);
const state = reactive<MenuStated>({
collapsed,
selectedKeys,
openKeys,
});
const setCollapsed = (collapsed = false) => {
state.collapsed = collapsed;
};
const setSelectedKeys = (selectedKeys: string[]) => {
state.selectedKeys = selectedKeys;
};
const setOpenKeys = (openKeys: string[]) => {
state.openKeys = openKeys;
};
provide(MenuStateKey, {
...toRefs(state),
setCollapsed,
setSelectedKeys,
setOpenKeys,
});
const watchRef = watch(
() => state.collapsed,
collapsed => {
if (collapsed) {
cacheKeys.value = state.openKeys.concat();
state.openKeys = [];
} else {
state.openKeys = cacheKeys.value.concat();
}
},
);
return [state, { setCollapsed, setSelectedKeys, setOpenKeys }, watchRef] as MenuStateWatched;
}
export function useMenuState(): Readonly<ToRefs<MenuStated>> & MenuHandles {
return inject(MenuStateKey);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment