提交 97180e83 作者: vben

feat(layout): added setting. Used to fix the left mixed mode menu

上级 5091a875
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
### ✨ Features ### ✨ Features
- 新增`mixSideTrigger`配置。用于配置左侧混合模式菜单打开方式。可选`hover`,默认`click` - 新增`mixSideTrigger`配置。用于配置左侧混合模式菜单打开方式。可选`hover`,默认`click`
- 新增`mixSideFixed`配置。用于固定左侧混合模式菜单
- modal 组件新增`height``min-height`属性
### 🐛 Bug Fixes ### 🐛 Bug Fixes
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
"build": "cross-env vite build --mode=production && esno ./build/script/postBuild.ts", "build": "cross-env vite build --mode=production && esno ./build/script/postBuild.ts",
"build:site": "cross-env SITE=true npm run build ", "build:site": "cross-env SITE=true npm run build ",
"build:no-cache": "yarn clean:cache && npm run build", "build:no-cache": "yarn clean:cache && npm run build",
"typecheck": "typecheck .", "typecheck": "vuedx-typecheck .",
"report": "cross-env REPORT=true npm run build ", "report": "cross-env REPORT=true npm run build ",
"preview": "npm run build && esno ./build/script/preview.ts", "preview": "npm run build && esno ./build/script/preview.ts",
"preview:dist": "esno ./build/script/preview.ts", "preview:dist": "esno ./build/script/preview.ts",
......
...@@ -125,15 +125,13 @@ ...@@ -125,15 +125,13 @@
} }
}); });
watch( !props.mixSider &&
() => props.items, watch(
() => { () => props.items,
handleMenuChange(); () => {
} handleMenuChange();
// { }
// immediate: true, );
// }
);
async function handleMenuClick({ key, keyPath }: { key: string; keyPath: string[] }) { async function handleMenuClick({ key, keyPath }: { key: string; keyPath: string[] }) {
const { beforeClickFn } = props; const { beforeClickFn } = props;
......
...@@ -8,6 +8,7 @@ import { unref } from 'vue'; ...@@ -8,6 +8,7 @@ import { unref } from 'vue';
import { es6Unique } from '/@/utils'; import { es6Unique } from '/@/utils';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { getAllParentPath } from '/@/router/helper/menuHelper'; import { getAllParentPath } from '/@/router/helper/menuHelper';
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
export function useOpenKeys( export function useOpenKeys(
menuState: MenuState, menuState: MenuState,
...@@ -15,18 +16,29 @@ export function useOpenKeys( ...@@ -15,18 +16,29 @@ export function useOpenKeys(
mode: Ref<MenuModeEnum>, mode: Ref<MenuModeEnum>,
accordion: Ref<boolean> accordion: Ref<boolean>
) { ) {
const { getCollapsed, getIsMixSidebar } = useMenuSetting(); const { getCollapsed, getIsMixSidebar, getMixSideFixed } = useMenuSetting();
function setOpenKeys(path: string) { async function setOpenKeys(path: string) {
if (mode.value === MenuModeEnum.HORIZONTAL) { if (mode.value === MenuModeEnum.HORIZONTAL) {
return; return;
} }
const menuList = toRaw(menus.value); const native = unref(getIsMixSidebar) && unref(getMixSideFixed);
if (!unref(accordion)) {
menuState.openKeys = es6Unique([...menuState.openKeys, ...getAllParentPath(menuList, path)]); useTimeoutFn(
} else { () => {
menuState.openKeys = getAllParentPath(menuList, path); const menuList = toRaw(menus.value);
} if (!unref(accordion)) {
menuState.openKeys = es6Unique([
...menuState.openKeys,
...getAllParentPath(menuList, path),
]);
} else {
menuState.openKeys = getAllParentPath(menuList, path);
}
},
16,
native
);
} }
const getOpenKeys = computed(() => { const getOpenKeys = computed(() => {
......
...@@ -218,7 +218,7 @@ export function useDataSource( ...@@ -218,7 +218,7 @@ export function useDataSource(
onMounted(() => { onMounted(() => {
useTimeoutFn(() => { useTimeoutFn(() => {
unref(propsRef).immediate && fetch(); unref(propsRef).immediate && fetch();
}, 0); }, 16);
}); });
return { return {
......
...@@ -3,20 +3,23 @@ import { tryOnUnmounted } from '/@/utils/helper/vueHelper'; ...@@ -3,20 +3,23 @@ import { tryOnUnmounted } from '/@/utils/helper/vueHelper';
import { isFunction } from '/@/utils/is'; import { isFunction } from '/@/utils/is';
export function useTimeoutFn(handle: Fn<any>, wait: number) { export function useTimeoutFn(handle: Fn<any>, wait: number, native = false) {
if (!isFunction(handle)) { if (!isFunction(handle)) {
throw new Error('handle is not Function!'); throw new Error('handle is not Function!');
} }
const { readyRef, stop, start } = useTimeoutRef(wait); const { readyRef, stop, start } = useTimeoutRef(wait);
if (native) {
watch( handle();
readyRef, } else {
(maturity) => { watch(
maturity && handle(); readyRef,
}, (maturity) => {
{ immediate: false } maturity && handle();
); },
{ immediate: false }
);
}
return { readyRef, stop, start }; return { readyRef, stop, start };
} }
......
import type { MenuSetting } from '/@/types/config'; import type { MenuSetting } from '/@/types/config';
import { computed, unref } from 'vue'; import { computed, unref, ref } from 'vue';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
...@@ -8,6 +8,8 @@ import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appE ...@@ -8,6 +8,8 @@ import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appE
import { MenuModeEnum, MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum'; import { MenuModeEnum, MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum';
import { useFullContent } from '/@/hooks/web/useFullContent'; import { useFullContent } from '/@/hooks/web/useFullContent';
const mixSideHasChildren = ref(false);
// Get menu configuration // Get menu configuration
const getMenuSetting = computed(() => appStore.getProjectConfig.menuSetting); const getMenuSetting = computed(() => appStore.getProjectConfig.menuSetting);
...@@ -39,6 +41,8 @@ const getCanDrag = computed(() => unref(getMenuSetting).canDrag); ...@@ -39,6 +41,8 @@ const getCanDrag = computed(() => unref(getMenuSetting).canDrag);
const getAccordion = computed(() => unref(getMenuSetting).accordion); const getAccordion = computed(() => unref(getMenuSetting).accordion);
const getMixSideFixed = computed(() => unref(getMenuSetting).mixSideFixed);
const getTopMenuAlign = computed(() => unref(getMenuSetting).topMenuAlign); const getTopMenuAlign = computed(() => unref(getMenuSetting).topMenuAlign);
const getCloseMixSidebarOnChange = computed(() => unref(getMenuSetting).closeMixSidebarOnChange); const getCloseMixSidebarOnChange = computed(() => unref(getMenuSetting).closeMixSidebarOnChange);
...@@ -87,7 +91,8 @@ const getCalcContentWidth = computed(() => { ...@@ -87,7 +91,8 @@ const getCalcContentWidth = computed(() => {
unref(getIsTopMenu) || !unref(getShowMenu) || (unref(getSplit) && unref(getMenuHidden)) unref(getIsTopMenu) || !unref(getShowMenu) || (unref(getSplit) && unref(getMenuHidden))
? 0 ? 0
: unref(getIsMixSidebar) : unref(getIsMixSidebar)
? SIDE_BAR_SHOW_TIT_MINI_WIDTH ? SIDE_BAR_SHOW_TIT_MINI_WIDTH +
(unref(getMixSideFixed) && unref(mixSideHasChildren) ? unref(getRealWidth) : 0)
: unref(getRealWidth); : unref(getRealWidth);
return `calc(100% - ${unref(width)}px)`; return `calc(100% - ${unref(width)}px)`;
...@@ -148,5 +153,7 @@ export function useMenuSetting() { ...@@ -148,5 +153,7 @@ export function useMenuSetting() {
getIsMixSidebar, getIsMixSidebar,
getCloseMixSidebarOnChange, getCloseMixSidebarOnChange,
getMixSideTrigger, getMixSideTrigger,
getMixSideFixed,
mixSideHasChildren,
}; };
} }
...@@ -75,6 +75,7 @@ export default defineComponent({ ...@@ -75,6 +75,7 @@ export default defineComponent({
getIsMixSidebar, getIsMixSidebar,
getCloseMixSidebarOnChange, getCloseMixSidebarOnChange,
getMixSideTrigger, getMixSideTrigger,
getMixSideFixed,
} = useMenuSetting(); } = useMenuSetting();
const { const {
...@@ -110,6 +111,12 @@ export default defineComponent({ ...@@ -110,6 +111,12 @@ export default defineComponent({
def={unref(getSplit)} def={unref(getSplit)}
disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX} disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX}
/> />
<SwitchItem
title={t('layout.setting.mixSidebarFixed')}
event={HandlerEnum.MENU_FIXED_MIX_SIDEBAR}
def={unref(getMixSideFixed)}
disabled={!unref(getIsMixSidebar)}
/>
<SwitchItem <SwitchItem
title={t('layout.setting.closeMixSidebarOnChange')} title={t('layout.setting.closeMixSidebarOnChange')}
......
...@@ -27,6 +27,7 @@ export enum HandlerEnum { ...@@ -27,6 +27,7 @@ export enum HandlerEnum {
MENU_FIXED, MENU_FIXED,
MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE, MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE,
MENU_TRIGGER_MIX_SIDEBAR, MENU_TRIGGER_MIX_SIDEBAR,
MENU_FIXED_MIX_SIDEBAR,
// header // header
HEADER_SHOW, HEADER_SHOW,
......
...@@ -70,6 +70,9 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf ...@@ -70,6 +70,9 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
case HandlerEnum.MENU_TRIGGER_MIX_SIDEBAR: case HandlerEnum.MENU_TRIGGER_MIX_SIDEBAR:
return { menuSetting: { mixSideTrigger: value } }; return { menuSetting: { mixSideTrigger: value } };
case HandlerEnum.MENU_FIXED_MIX_SIDEBAR:
return { menuSetting: { mixSideTrigger: value } };
// ============transition================== // ============transition==================
case HandlerEnum.OPEN_PAGE_LOADING: case HandlerEnum.OPEN_PAGE_LOADING:
appStore.commitPageLoadingState(false); appStore.commitPageLoadingState(false);
......
<template> <template>
<div :class="`${prefixCls}-dom`" /> <div :class="`${prefixCls}-dom`" :style="getDomStyle" />
<div <div
v-click-outside="handleClickOutside" v-click-outside="handleClickOutside"
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
v-bind="getItemEvents(item)" v-bind="getItemEvents(item)"
> >
<MenuTag :item="item" :showTitle="false" :isHorizontal="false" /> <MenuTag :item="item" :showTitle="false" :isHorizontal="false" />
<g-icon <Icon
:class="`${prefixCls}-module__icon`" :class="`${prefixCls}-module__icon`"
:size="22" :size="22"
:icon="item.meta && item.meta.icon" :icon="item.meta && item.meta.icon"
...@@ -48,6 +48,14 @@ ...@@ -48,6 +48,14 @@
]" ]"
> >
<span class="text"> {{ title }}</span> <span class="text"> {{ title }}</span>
<Icon
:size="16"
v-if="getMixSideFixed"
icon="ri:pushpin-2-fill"
class="pushpin"
@click="handleFixedMenu"
/>
<Icon :size="16" v-else icon="ri:pushpin-2-line" class="pushpin" @click="handleFixedMenu" />
</div> </div>
<ScrollContainer :class="`${prefixCls}-menu-list__content`"> <ScrollContainer :class="`${prefixCls}-menu-list__content`">
<BasicMenu <BasicMenu
...@@ -70,20 +78,23 @@ ...@@ -70,20 +78,23 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, onMounted, ref, computed, CSSProperties, unref } from 'vue'; import { defineComponent, onMounted, ref, computed, CSSProperties, unref } from 'vue';
import type { Menu } from '/@/router/types'; import type { Menu } from '/@/router/types';
import type { RouteLocationNormalized } from 'vue-router'; import { RouteLocationNormalized } from 'vue-router';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { getShallowMenus, getChildrenMenus, getCurrentParentPath } from '/@/router/menus'; import { getShallowMenus, getChildrenMenus, getCurrentParentPath } from '/@/router/menus';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { ScrollContainer } from '/@/components/Container'; import { ScrollContainer } from '/@/components/Container';
import Icon from '/@/components/Icon';
import { AppLogo } from '/@/components/Application'; import { AppLogo } from '/@/components/Application';
import { useGo } from '/@/hooks/web/usePage'; import { useGo } from '/@/hooks/web/usePage';
import { BasicMenu, MenuTag } from '/@/components/Menu'; import { BasicMenu, MenuTag } from '/@/components/Menu';
import { listenerLastChangeTab } from '/@/logics/mitt/tabChange'; import { listenerLastChangeTab } from '/@/logics/mitt/tabChange';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useDragLine } from './useLayoutSider'; import { useDragLine } from './useLayoutSider';
import { useGlobSetting } from '/@/hooks/setting';
import { SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum';
import clickOutside from '/@/directives/clickOutside'; import clickOutside from '/@/directives/clickOutside';
import { useGlobSetting } from '/@/hooks/setting';
export default defineComponent({ export default defineComponent({
name: 'LayoutMixSider', name: 'LayoutMixSider',
...@@ -92,6 +103,7 @@ ...@@ -92,6 +103,7 @@
AppLogo, AppLogo,
BasicMenu, BasicMenu,
MenuTag, MenuTag,
Icon,
}, },
directives: { directives: {
clickOutside, clickOutside,
...@@ -101,6 +113,7 @@ ...@@ -101,6 +113,7 @@
const activePath = ref(''); const activePath = ref('');
const chilrenMenus = ref<Menu[]>([]); const chilrenMenus = ref<Menu[]>([]);
const openMenu = ref(false); const openMenu = ref(false);
const isInit = ref(false);
const dragBarRef = ref<ElRef>(null); const dragBarRef = ref<ElRef>(null);
const sideRef = ref<ElRef>(null); const sideRef = ref<ElRef>(null);
const currentRoute = ref<Nullable<RouteLocationNormalized>>(null); const currentRoute = ref<Nullable<RouteLocationNormalized>>(null);
...@@ -114,7 +127,12 @@ ...@@ -114,7 +127,12 @@
getCloseMixSidebarOnChange, getCloseMixSidebarOnChange,
getMenuTheme, getMenuTheme,
getMixSideTrigger, getMixSideTrigger,
getRealWidth,
getMixSideFixed,
mixSideHasChildren,
setMenuSetting,
} = useMenuSetting(); } = useMenuSetting();
const { title } = useGlobSetting(); const { title } = useGlobSetting();
useDragLine(sideRef, dragBarRef, true); useDragLine(sideRef, dragBarRef, true);
...@@ -127,14 +145,41 @@ ...@@ -127,14 +145,41 @@
} }
); );
const getIsFixed = computed(() => {
mixSideHasChildren.value = unref(chilrenMenus).length > 0;
const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren);
if (isFixed) {
openMenu.value = true;
}
return isFixed;
});
const getDomStyle = computed(
(): CSSProperties => {
const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0;
const width = `${SIDE_BAR_SHOW_TIT_MINI_WIDTH + fixedWidth}px`;
return {
width,
maxWidth: width,
minWidth: width,
flex: `0 0 ${width}`,
};
}
);
const getMenuEvents = computed(() => { const getMenuEvents = computed(() => {
return unref(getMixSideTrigger) === 'hover' // return unref(getMixSideTrigger) === 'hover'
? { // ? {
onMouseleave: () => { // onMouseleave: () => {
openMenu.value = false; // closeMenu();
}, // },
} // }
: {}; // : {};
return {
onMouseleave: () => {
closeMenu();
},
};
}); });
const getShowDragBar = computed(() => unref(getCanDrag)); const getShowDragBar = computed(() => unref(getCanDrag));
...@@ -145,9 +190,9 @@ ...@@ -145,9 +190,9 @@
listenerLastChangeTab((route) => { listenerLastChangeTab((route) => {
currentRoute.value = route; currentRoute.value = route;
setActive(); setActive(true);
if (unref(getCloseMixSidebarOnChange)) { if (unref(getCloseMixSidebarOnChange)) {
openMenu.value = false; closeMenu();
} }
}); });
...@@ -156,7 +201,11 @@ ...@@ -156,7 +201,11 @@
if (unref(activePath) === path) { if (unref(activePath) === path) {
if (!hover) { if (!hover) {
openMenu.value = !unref(openMenu); if (!unref(openMenu)) {
openMenu.value = true;
} else {
closeMenu();
}
} }
if (!unref(openMenu)) { if (!unref(openMenu)) {
setActive(); setActive();
...@@ -169,18 +218,32 @@ ...@@ -169,18 +218,32 @@
if (!children || children.length === 0) { if (!children || children.length === 0) {
go(path); go(path);
chilrenMenus.value = []; chilrenMenus.value = [];
openMenu.value = false; closeMenu();
return; return;
} }
chilrenMenus.value = children; chilrenMenus.value = children;
} }
async function setActive() { async function setActive(setChildren = false) {
const path = currentRoute.value?.path; const path = currentRoute.value?.path;
if (!path) return; if (!path) return;
const parentPath = await getCurrentParentPath(path); const parentPath = await getCurrentParentPath(path);
activePath.value = parentPath; activePath.value = parentPath;
// hanldeModuleClick(parentPath); // hanldeModuleClick(parentPath);
if (unref(getMixSideFixed)) {
const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath));
const p = activeMenu?.path;
if (p) {
const children = await getChildrenMenus(p);
if (setChildren) {
chilrenMenus.value = children;
openMenu.value = children.length > 0;
}
if (children.length === 0) {
chilrenMenus.value = [];
}
}
}
} }
function handleMenuClick(path: string) { function handleMenuClick(path: string) {
...@@ -188,7 +251,7 @@ ...@@ -188,7 +251,7 @@
} }
function handleClickOutside() { function handleClickOutside() {
openMenu.value = false; closeMenu();
setActive(); setActive();
} }
...@@ -203,6 +266,18 @@ ...@@ -203,6 +266,18 @@
}; };
} }
function handleFixedMenu() {
setMenuSetting({
mixSideFixed: !unref(getIsFixed),
});
}
function closeMenu() {
if (!unref(getIsFixed)) {
openMenu.value = false;
}
}
return { return {
t, t,
prefixCls, prefixCls,
...@@ -221,6 +296,9 @@ ...@@ -221,6 +296,9 @@
getMenuTheme, getMenuTheme,
getItemEvents, getItemEvents,
getMenuEvents, getMenuEvents,
getDomStyle,
handleFixedMenu,
getMixSideFixed,
}; };
}, },
}); });
...@@ -241,7 +319,7 @@ ...@@ -241,7 +319,7 @@
min-width: @width; min-width: @width;
overflow: hidden; overflow: hidden;
background: @sider-dark-bg-color; background: @sider-dark-bg-color;
transition: all 0.2s ease 0s; transition: all 0.3s ease 0s;
flex: 0 0 @width; flex: 0 0 @width;
.@{tag-prefix-cls} { .@{tag-prefix-cls} {
position: absolute; position: absolute;
...@@ -293,6 +371,17 @@ ...@@ -293,6 +371,17 @@
} }
} }
} }
.@{prefix-cls}-menu-list {
&__title {
.pushpin {
color: rgba(0, 0, 0, 0.35);
&:hover {
color: rgba(0, 0, 0, 0.85);
}
}
}
}
} }
@border-color: @sider-dark-lighten-1-bg-color; @border-color: @sider-dark-lighten-1-bg-color;
...@@ -388,20 +477,30 @@ ...@@ -388,20 +477,30 @@
&__title { &__title {
display: flex; display: flex;
height: @header-height; height: @header-height;
margin-left: -6px; // margin-left: -6px;
font-size: 18px; font-size: 18px;
color: @primary-color; color: @primary-color;
border-bottom: 1px solid rgb(238, 238, 238); border-bottom: 1px solid rgb(238, 238, 238);
opacity: 0; opacity: 0;
transition: unset; transition: unset;
// justify-content: center;
align-items: center; align-items: center;
justify-content: start; justify-content: space-between;
&.show { &.show {
min-width: 130px;
opacity: 1; opacity: 1;
transition: all 0.5s ease; transition: all 0.5s ease;
} }
.pushpin {
margin-right: 6px;
color: rgba(255, 255, 255, 0.65);
cursor: pointer;
&:hover {
color: #fff;
}
}
} }
&__content { &__content {
......
...@@ -77,4 +77,6 @@ export default { ...@@ -77,4 +77,6 @@ export default {
mixSidebarTrigger: 'Mixed menu Trigger', mixSidebarTrigger: 'Mixed menu Trigger',
triggerHover: 'Hover', triggerHover: 'Hover',
triggerClick: 'Click', triggerClick: 'Click',
mixSidebarFixed: 'Fixed expanded menu',
}; };
...@@ -76,4 +76,6 @@ export default { ...@@ -76,4 +76,6 @@ export default {
mixSidebarTrigger: '混合菜单触发方式', mixSidebarTrigger: '混合菜单触发方式',
triggerHover: '悬停', triggerHover: '悬停',
triggerClick: '点击', triggerClick: '点击',
mixSidebarFixed: '固定展开菜单',
}; };
...@@ -110,6 +110,8 @@ const setting: ProjectConfig = { ...@@ -110,6 +110,8 @@ const setting: ProjectConfig = {
closeMixSidebarOnChange: false, closeMixSidebarOnChange: false,
// Module opening method ‘click’ |'hover' // Module opening method ‘click’ |'hover'
mixSideTrigger: MixSidebarTriggerEnum.CLICK, mixSideTrigger: MixSidebarTriggerEnum.CLICK,
// Fixed expanded menu
mixSideFixed: false,
}, },
// Multi-label // Multi-label
......
...@@ -21,6 +21,7 @@ export interface MenuSetting { ...@@ -21,6 +21,7 @@ export interface MenuSetting {
closeMixSidebarOnChange: boolean; closeMixSidebarOnChange: boolean;
collapsedShowTitle: boolean; collapsedShowTitle: boolean;
mixSideTrigger: MixSidebarTriggerEnum; mixSideTrigger: MixSidebarTriggerEnum;
mixSideFixed: boolean;
} }
export interface MultiTabsSetting { export interface MultiTabsSetting {
......
{ {
"compilerOptions": { "compilerOptions": {
"target": "es2016", "target": "esnext",
"module": "esnext", "module": "esnext",
"moduleResolution": "node", "moduleResolution": "node",
"strict": true, "strict": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"strictFunctionTypes": false, "strictFunctionTypes": false,
"jsx": "react", "jsx": "preserve",
"baseUrl": ".", "baseUrl": ".",
"allowJs": true, "allowJs": true,
"sourceMap": true, "sourceMap": true,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论