fix(projects): 修复vertical-mix导航模式的二级菜单显示问题

This commit is contained in:
Soybean 2021-09-29 08:49:28 +08:00
parent c7e6b86a5b
commit 6f286e6747
10 changed files with 1443 additions and 979 deletions

View File

@ -23,21 +23,21 @@
"chroma-js": "^2.1.2",
"dayjs": "^1.10.7",
"form-data": "^4.0.0",
"naive-ui": "^2.19.2",
"naive-ui": "^2.19.3",
"pinia": "^2.0.0-rc.4",
"qs": "^6.10.1",
"vue": "^3.2.10",
"vue-router": "^4.0.11"
},
"devDependencies": {
"@commitlint/cli": "^13.1.0",
"@commitlint/config-conventional": "^13.1.0",
"@iconify/json": "^1.1.406",
"@commitlint/cli": "^13.2.0",
"@commitlint/config-conventional": "^13.2.0",
"@iconify/json": "^1.1.407",
"@iconify/vue": "^3.0.0",
"@types/chroma-js": "^2.1.3",
"@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "^4.31.2",
"@typescript-eslint/parser": "^4.31.2",
"@typescript-eslint/eslint-plugin": "^4.32.0",
"@typescript-eslint/parser": "^4.32.0",
"@vicons/antd": "^0.11.0",
"@vicons/carbon": "^0.11.0",
"@vicons/fa": "^0.11.0",
@ -70,11 +70,11 @@
"unplugin-icons": "^0.11.4",
"unplugin-vue-components": "^0.15.4",
"vite": "^2.5.10",
"vite-plugin-html": "^2.1.0",
"vite-plugin-windicss": "^1.4.7",
"vite-plugin-html": "^2.1.1",
"vite-plugin-windicss": "^1.4.8",
"vue-tsc": "^0.3.0",
"vueuc": "^0.4.12",
"windicss": "^3.1.7"
"windicss": "^3.1.8"
},
"config": {
"commitizen": {

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,6 @@ export default function useReloadContext() {
}
return {
context,
useReloadProvide,
useReloadInject
};

View File

@ -1 +1,3 @@
export { setupAppContext, useReloadInject } from './app';
export { useVerticalMixSiderContext } from './part';

View File

@ -0,0 +1,3 @@
import useVerticalMixSiderContext from './useVerticalMixSiderContext';
export { useVerticalMixSiderContext };

View File

@ -0,0 +1,54 @@
import { ref } from 'vue';
import type { Ref } from 'vue';
import { useContext, useBoolean } from '@/hooks';
interface VerticalMixSiderContext {
/** 子菜单可见性 */
childMenuVisible: Ref<boolean>;
/** 展示子菜单 */
showChildMenu(): void;
/** 隐藏子菜单 */
hideChildMenu(): void;
/** 鼠标悬浮的一级菜单对应的路由名称 */
hoverRouteName: Ref<string>;
/** 设置悬浮路由名称 */
setHoverRouteName(name: string): void;
isMouseEnterChildMenu: Ref<boolean>;
setMouseEnterChildMenu(): void;
setMouseLeaveChildMenu(): void;
}
const { useProvide, useInject: useVerticalMixSiderInject } = useContext<VerticalMixSiderContext>();
export default function useVerticalMixSiderContext() {
const { bool: childMenuVisible, setTrue: showChildMenu, setFalse: hideChildMenu } = useBoolean();
const {
bool: isMouseEnterChildMenu,
setTrue: setMouseEnterChildMenu,
setFalse: setMouseLeaveChildMenu
} = useBoolean();
const hoverRouteName = ref('');
function setHoverRouteName(name: string) {
hoverRouteName.value = name;
}
const context: VerticalMixSiderContext = {
childMenuVisible,
showChildMenu,
hideChildMenu,
hoverRouteName,
setHoverRouteName,
isMouseEnterChildMenu,
setMouseEnterChildMenu,
setMouseLeaveChildMenu
};
function useVerticalMixSiderProvide() {
useProvide(context);
}
return {
useVerticalMixSiderProvide,
useVerticalMixSiderInject
};
}

View File

@ -21,10 +21,12 @@
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import { computed } from 'vue';
import type { PropType, VNodeChild } from 'vue';
import { useRouter } from 'vue-router';
import { useAppStore } from '@/store';
import { useBoolean } from '@/hooks';
import { useVerticalMixSiderContext } from '@/context';
const props = defineProps({
routeName: {
@ -39,51 +41,50 @@ const props = defineProps({
type: Function as PropType<() => VNodeChild>,
required: true
},
isActive: {
type: Boolean,
default: false
activeRouteName: {
type: String,
required: true
},
isMini: {
type: Boolean,
default: false
},
hoverRoute: {
type: String,
default: ''
}
});
const emit = defineEmits(['update:hoverRoute']);
const app = useAppStore();
const router = useRouter();
const { useVerticalMixSiderInject } = useVerticalMixSiderContext();
const { bool: isHover, setTrue, setFalse } = useBoolean();
const { bool: isMouseEnterMenu, setTrue: setMouseEnterMenu, setFalse: setMouseLeaveMenu } = useBoolean();
const hoverRouteName = ref(props.hoverRoute);
function setHoverRouteName(name: string) {
hoverRouteName.value = name;
}
const { setHoverRouteName, showChildMenu, hideChildMenu, isMouseEnterChildMenu } = useVerticalMixSiderInject();
const isActive = computed(() => props.routeName === props.activeRouteName);
function handleRouter() {
router.push({ name: props.routeName });
}
function handleMouseEvent(type: 'enter' | 'leave') {
if (type === 'enter') {
setTrue();
setHoverRouteName(props.routeName);
} else {
setFalse();
}
async function setActiveHoverRouteName() {
setTimeout(() => {
if (app.menu.fixedMix && !isMouseEnterChildMenu.value && !isMouseEnterMenu.value) {
setHoverRouteName(props.activeRouteName);
}
setMouseLeaveMenu();
}, 100);
}
watch(
() => props.hoverRoute,
newValue => {
setHoverRouteName(newValue);
function handleMouseEvent(type: 'enter' | 'leave') {
if (type === 'enter') {
setMouseEnterMenu();
setTrue();
setHoverRouteName(props.routeName);
showChildMenu();
} else {
setFalse();
hideChildMenu();
setActiveHoverRouteName();
}
);
watch(hoverRouteName, newValue => {
emit('update:hoverRoute', newValue);
});
}
</script>
<style scoped></style>

View File

@ -13,7 +13,8 @@
dark:bg-[#18181c]
"
:style="{ width: showDrawer ? theme.menuStyle.width + 'px' : '0px' }"
@mouseleave="handleResetHoverRoute"
@mouseenter="handleMouseEvent('enter')"
@mouseleave="handleMouseEvent('leave')"
>
<header class="header-height flex-y-center justify-between">
<h2 class="pl-8px text-16px text-primary font-bold">{{ title }}</h2>
@ -38,29 +39,39 @@ import { NScrollbar, NMenu } from 'naive-ui';
import type { MenuOption } from 'naive-ui';
import { useThemeStore, useAppStore } from '@/store';
import { useAppTitle } from '@/hooks';
import { useVerticalMixSiderContext } from '@/context';
import { menus } from '@/router';
import type { GlobalMenuOption } from '@/interface';
const props = defineProps({
hoverRoute: {
activeRouteName: {
type: String,
default: ''
required: true
}
});
const emit = defineEmits(['reset-hover-route']);
const router = useRouter();
const route = useRoute();
const theme = useThemeStore();
const app = useAppStore();
const { toggleFixedMixMenu } = useAppStore();
const { useVerticalMixSiderInject } = useVerticalMixSiderContext();
const title = useAppTitle();
const {
childMenuVisible,
hoverRouteName,
setHoverRouteName,
showChildMenu,
hideChildMenu,
setMouseEnterChildMenu,
setMouseLeaveChildMenu
} = useVerticalMixSiderInject();
const childMenus = computed(() => {
const children: MenuOption[] = [];
menus.some(item => {
const flag = item.routeName === props.hoverRoute && Boolean(item.children?.length);
const flag = item.routeName === hoverRouteName.value && Boolean(item.children?.length);
if (flag) {
children.push(...item.children!);
}
@ -69,17 +80,9 @@ const childMenus = computed(() => {
return children;
});
const showDrawer = computed(() => childMenus.value.length || app.menu.fixedMix);
const showDrawer = computed(() => (childMenuVisible.value && childMenus.value.length) || app.menu.fixedMix);
const activeKey = computed(() => getActiveKey());
function getActiveKey() {
return route.name as string;
}
function handleResetHoverRoute() {
emit('reset-hover-route');
}
const activeKey = computed(() => route.name as string);
function handleUpdateMenu(key: string, item: MenuOption) {
const menuItem = item as GlobalMenuOption;
@ -90,6 +93,17 @@ const headerHeight = computed(() => {
const { height } = theme.headerStyle;
return `${height}px`;
});
function handleMouseEvent(type: 'enter' | 'leave') {
if (type === 'enter') {
showChildMenu();
setMouseEnterChildMenu();
} else {
hideChildMenu();
setMouseLeaveChildMenu();
setHoverRouteName(props.activeRouteName);
}
}
</script>
<style scoped>
.drawer-shadow {

View File

@ -10,11 +10,10 @@
<mix-menu
v-for="item in firstDegreeMenus"
:key="item.routeName"
v-model:hover-route="hoverRoute"
:route-name="item.routeName"
:label="item.label"
:icon="item.icon"
:is-active="activeParentRouteName === item.routeName"
:active-route-name="activeParentRouteName"
:is-mini="app.menu.collapsed"
/>
</n-scrollbar>
@ -25,17 +24,18 @@
class="relative h-full transition-width duration-300 ease-in-out"
:style="{ width: app.menu.fixedMix ? theme.menuStyle.width + 'px' : '0px' }"
>
<mix-menu-drawer :hover-route="hoverRoute" @reset-hover-route="resetHoverRoute" />
<mix-menu-drawer :active-route-name="activeParentRouteName" />
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { computed } from 'vue';
import type { VNodeChild } from 'vue';
import { NScrollbar } from 'naive-ui';
import { useRoute } from 'vue-router';
import { useAppStore, useThemeStore } from '@/store';
import { useVerticalMixSiderContext } from '@/context';
import { menus } from '@/router';
import { MixMenu, MixMenuCollapse, MixMenuDrawer } from './components';
import { GlobalLogo } from '../../../common';
@ -43,6 +43,7 @@ import { GlobalLogo } from '../../../common';
const theme = useThemeStore();
const app = useAppStore();
const route = useRoute();
const { useVerticalMixSiderProvide } = useVerticalMixSiderContext();
const mixMenuWidth = computed(() => `${theme.menuStyle.mixWidth}px`);
const mixMenuCollapsedWidth = computed(() => `${theme.menuStyle.mixCollapsedWidth}px`);
@ -68,10 +69,7 @@ const activeParentRouteName = computed(() => {
return name;
});
const hoverRoute = ref('');
function resetHoverRoute() {
hoverRoute.value = '';
}
useVerticalMixSiderProvide();
</script>
<style scoped>
.mix-menu-width {

View File

@ -43,7 +43,7 @@ const notification = useNotification();
const formRef = ref<(HTMLElement & FormInst) | null>(null);
const model = reactive({
phone: '15170283876',
phone: '15100000000',
pwd: '123456'
});
const rules = {