mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-11-15 14:03:36 +08:00
perf: 优化导航样式以及菜单折叠动画 (#408)
* chore: `4.0.0` 版本,正在开发中 * chore: update `element-plus` * chore: update * chore: update dependencies * chore: update * style: update * chore: update `dependencies` * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useFullscreen } from "@vueuse/core";
|
||||
|
||||
const { t } = useI18n();
|
||||
const { isFullscreen, toggle } = useFullscreen();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="screen-full w-[36px] h-[48px] flex-ac cursor-pointer navbar-bg-hover"
|
||||
@click="toggle"
|
||||
>
|
||||
<FontIcon
|
||||
:title="
|
||||
isFullscreen ? t('buttons.hsexitfullscreen') : t('buttons.hsfullscreen')
|
||||
"
|
||||
:icon="isFullscreen ? 'team-iconexit-fullscreen' : 'team-iconfullscreen'"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -46,7 +46,11 @@ watch(
|
||||
class="horizontal-header"
|
||||
>
|
||||
<div class="horizontal-header-left" @click="backHome">
|
||||
<FontIcon icon="team-iconlogo" svg style="width: 35px; height: 35px" />
|
||||
<FontIcon
|
||||
icon="pure-iconfont-logo"
|
||||
svg
|
||||
style="width: 35px; height: 35px"
|
||||
/>
|
||||
<h4>{{ title }}</h4>
|
||||
</div>
|
||||
<el-menu
|
||||
|
||||
@@ -24,7 +24,7 @@ const iconClass = computed(() => {
|
||||
"align-middle",
|
||||
"text-primary",
|
||||
"cursor-pointer",
|
||||
"duration-[360ms]",
|
||||
"duration-[100ms]",
|
||||
"hover:text-primary",
|
||||
"dark:hover:!text-white"
|
||||
];
|
||||
|
||||
@@ -18,7 +18,11 @@ const { title } = useNav();
|
||||
class="sidebar-logo-link"
|
||||
to="/"
|
||||
>
|
||||
<FontIcon icon="team-iconlogo" svg style="width: 35px; height: 35px" />
|
||||
<FontIcon
|
||||
icon="pure-iconfont-logo"
|
||||
svg
|
||||
style="width: 35px; height: 35px"
|
||||
/>
|
||||
<span class="sidebar-title">{{ title }}</span>
|
||||
</router-link>
|
||||
<router-link
|
||||
@@ -28,7 +32,11 @@ const { title } = useNav();
|
||||
class="sidebar-logo-link"
|
||||
to="/"
|
||||
>
|
||||
<FontIcon icon="team-iconlogo" svg style="width: 35px; height: 35px" />
|
||||
<FontIcon
|
||||
icon="pure-iconfont-logo"
|
||||
svg
|
||||
style="width: 35px; height: 35px"
|
||||
/>
|
||||
<span class="sidebar-title">{{ title }}</span>
|
||||
</router-link>
|
||||
</transition>
|
||||
|
||||
@@ -28,17 +28,11 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const getExtraIconStyle = computed((): CSSProperties => {
|
||||
if (!isCollapse.value) {
|
||||
return {
|
||||
position: "absolute",
|
||||
right: "10px"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
position: "static"
|
||||
};
|
||||
}
|
||||
const getSpanStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
width: "100%",
|
||||
textAlign: "center"
|
||||
};
|
||||
});
|
||||
|
||||
const getNoDropdownStyle = computed((): CSSProperties => {
|
||||
@@ -48,16 +42,6 @@ const getNoDropdownStyle = computed((): CSSProperties => {
|
||||
};
|
||||
});
|
||||
|
||||
const getDivStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
width: !isCollapse.value ? "" : "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
overflow: "hidden"
|
||||
};
|
||||
});
|
||||
|
||||
const getMenuTextStyle = computed(() => {
|
||||
return {
|
||||
overflow: "hidden",
|
||||
@@ -66,22 +50,45 @@ const getMenuTextStyle = computed(() => {
|
||||
};
|
||||
});
|
||||
|
||||
const getSubTextStyle = computed((): CSSProperties => {
|
||||
const getDivStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
width: !isCollapse.value ? "210px" : "",
|
||||
display: "inline-block",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis"
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
overflow: "hidden"
|
||||
};
|
||||
});
|
||||
|
||||
const getSpanStyle = computed(() => {
|
||||
const getsubMenuIconStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis"
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
margin:
|
||||
layout.value === "horizontal"
|
||||
? "0 5px 0 0"
|
||||
: isCollapse.value
|
||||
? "0 auto"
|
||||
: "0 5px 0 0"
|
||||
};
|
||||
});
|
||||
|
||||
const getSubTextStyle = computed((): CSSProperties => {
|
||||
if (!isCollapse.value) {
|
||||
return {
|
||||
width: "210px",
|
||||
display: "inline-block",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
width: ""
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const expandCloseIcon = computed(() => {
|
||||
if (!getConfig()?.MenuArrowIconNoTransition) return "";
|
||||
return {
|
||||
@@ -115,6 +122,20 @@ function hoverMenu(key) {
|
||||
});
|
||||
}
|
||||
|
||||
// 左侧菜单折叠后,当菜单没有图标时只显示第一个文字并加上省略号
|
||||
function overflowSlice(text, item?: any) {
|
||||
const newText =
|
||||
(text?.length > 1 ? text.toString().slice(0, 1) : text) + "...";
|
||||
if (item && !(isCollapse.value && item?.parentId === null)) {
|
||||
return layout.value === "mix" &&
|
||||
item?.pathList?.length === 2 &&
|
||||
isCollapse.value
|
||||
? newText
|
||||
: text;
|
||||
}
|
||||
return newText;
|
||||
}
|
||||
|
||||
function hasOneShowingChild(
|
||||
children: childrenType[] = [],
|
||||
parent: childrenType
|
||||
@@ -151,84 +172,84 @@ function resolvePath(routePath) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template
|
||||
<el-menu-item
|
||||
v-if="
|
||||
hasOneShowingChild(props.item.children, props.item) &&
|
||||
(!onlyOneChild.children || onlyOneChild.noShowingChildren)
|
||||
"
|
||||
:index="resolvePath(onlyOneChild.path)"
|
||||
:class="{ 'submenu-title-noDropdown': !isNest }"
|
||||
:style="getNoDropdownStyle"
|
||||
>
|
||||
<el-menu-item
|
||||
:index="resolvePath(onlyOneChild.path)"
|
||||
:class="{ 'submenu-title-noDropdown': !isNest }"
|
||||
:style="getNoDropdownStyle"
|
||||
<div
|
||||
v-if="toRaw(props.item.meta.icon)"
|
||||
class="sub-menu-icon"
|
||||
:style="getsubMenuIconStyle"
|
||||
>
|
||||
<div class="sub-menu-icon" v-if="toRaw(props.item.meta.icon)">
|
||||
<component
|
||||
:is="
|
||||
useRenderIcon(
|
||||
toRaw(onlyOneChild.meta.icon) ||
|
||||
(props.item.meta && toRaw(props.item.meta.icon))
|
||||
)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
isCollapse &&
|
||||
layout === 'vertical' &&
|
||||
props.item?.pathList?.length === 1
|
||||
<component
|
||||
:is="
|
||||
useRenderIcon(
|
||||
toRaw(onlyOneChild.meta.icon) ||
|
||||
(props.item.meta && toRaw(props.item.meta.icon))
|
||||
)
|
||||
"
|
||||
:style="getDivStyle"
|
||||
>
|
||||
<span :style="getMenuTextStyle">
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
v-if="
|
||||
!props.item?.meta.icon &&
|
||||
isCollapse &&
|
||||
layout === 'vertical' &&
|
||||
props.item?.pathList?.length === 1
|
||||
"
|
||||
:style="getSpanStyle"
|
||||
>
|
||||
{{ overflowSlice(transformI18n(onlyOneChild.meta.title)) }}
|
||||
</span>
|
||||
<span
|
||||
v-if="
|
||||
!onlyOneChild.meta.icon &&
|
||||
isCollapse &&
|
||||
layout === 'mix' &&
|
||||
props.item?.pathList?.length === 2
|
||||
"
|
||||
:style="getSpanStyle"
|
||||
>
|
||||
{{ overflowSlice(transformI18n(onlyOneChild.meta.title)) }}
|
||||
</span>
|
||||
<template #title>
|
||||
<div :style="getDivStyle">
|
||||
<span v-if="layout === 'horizontal'">
|
||||
{{ transformI18n(onlyOneChild.meta.title) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
isCollapse && layout === 'mix' && props.item?.pathList?.length === 2
|
||||
"
|
||||
:style="getDivStyle"
|
||||
>
|
||||
<span :style="getMenuTextStyle">
|
||||
{{ transformI18n(onlyOneChild.meta.title) }}
|
||||
</span>
|
||||
</div>
|
||||
<template #title>
|
||||
<div :style="getDivStyle">
|
||||
<span v-if="layout === 'horizontal'">
|
||||
<el-tooltip
|
||||
v-else
|
||||
placement="top"
|
||||
:effect="tooltipEffect"
|
||||
:offset="-10"
|
||||
:disabled="!onlyOneChild.showTooltip"
|
||||
>
|
||||
<template #content>
|
||||
{{ transformI18n(onlyOneChild.meta.title) }}
|
||||
</template>
|
||||
<span
|
||||
ref="menuTextRef"
|
||||
:style="getMenuTextStyle"
|
||||
@mouseover="hoverMenu(onlyOneChild)"
|
||||
>
|
||||
{{ transformI18n(onlyOneChild.meta.title) }}
|
||||
</span>
|
||||
<el-tooltip
|
||||
v-else
|
||||
placement="top"
|
||||
:effect="tooltipEffect"
|
||||
:offset="-10"
|
||||
:disabled="!onlyOneChild.showTooltip"
|
||||
>
|
||||
<template #content>
|
||||
{{ transformI18n(onlyOneChild.meta.title) }}
|
||||
</template>
|
||||
<span
|
||||
ref="menuTextRef"
|
||||
:style="getMenuTextStyle"
|
||||
@mouseover="hoverMenu(onlyOneChild)"
|
||||
>
|
||||
{{ transformI18n(onlyOneChild.meta.title) }}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<FontIcon
|
||||
v-if="onlyOneChild.meta.extraIcon"
|
||||
width="30px"
|
||||
height="30px"
|
||||
:style="getExtraIconStyle"
|
||||
:icon="onlyOneChild.meta.extraIcon.name"
|
||||
:svg="onlyOneChild.meta.extraIcon.svg ? true : false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-tooltip>
|
||||
<FontIcon
|
||||
v-if="onlyOneChild.meta.extraIcon"
|
||||
width="30px"
|
||||
height="30px"
|
||||
:icon="onlyOneChild.meta.extraIcon.name"
|
||||
:svg="onlyOneChild.meta.extraIcon.svg ? true : false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-sub-menu
|
||||
v-else
|
||||
@@ -237,7 +258,11 @@ function resolvePath(routePath) {
|
||||
:index="resolvePath(props.item.path)"
|
||||
>
|
||||
<template #title>
|
||||
<div v-if="toRaw(props.item.meta.icon)" class="sub-menu-icon">
|
||||
<div
|
||||
v-if="toRaw(props.item.meta.icon)"
|
||||
:style="getsubMenuIconStyle"
|
||||
class="sub-menu-icon"
|
||||
>
|
||||
<component
|
||||
:is="useRenderIcon(props.item.meta && toRaw(props.item.meta.icon))"
|
||||
/>
|
||||
@@ -255,21 +280,25 @@ function resolvePath(routePath) {
|
||||
<template #content>
|
||||
{{ transformI18n(props.item.meta.title) }}
|
||||
</template>
|
||||
<div
|
||||
<span
|
||||
v-if="
|
||||
!(
|
||||
isCollapse &&
|
||||
toRaw(props.item.meta.icon) &&
|
||||
props.item.parentId === null
|
||||
)
|
||||
"
|
||||
ref="menuTextRef"
|
||||
:style="getSubTextStyle"
|
||||
@mouseover="hoverMenu(props.item)"
|
||||
>
|
||||
<span :style="getSpanStyle">
|
||||
{{ transformI18n(props.item.meta.title) }}
|
||||
</span>
|
||||
</div>
|
||||
{{ overflowSlice(transformI18n(props.item.meta.title), props.item) }}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<FontIcon
|
||||
v-if="props.item.meta.extraIcon"
|
||||
width="30px"
|
||||
height="30px"
|
||||
style="position: absolute; right: 10px"
|
||||
:icon="props.item.meta.extraIcon.name"
|
||||
:svg="props.item.meta.extraIcon.svg ? true : false"
|
||||
/>
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background: var(--el-color-primary);
|
||||
animation: scheduleInWidth 400ms ease-in;
|
||||
animation: scheduleInWidth 200ms ease-in;
|
||||
}
|
||||
|
||||
/* 灵动模式下鼠标移出隐藏蓝色进度条 */
|
||||
@@ -292,5 +292,5 @@
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background: var(--el-color-primary);
|
||||
animation: scheduleOutWidth 400ms ease-in;
|
||||
animation: scheduleOutWidth 200ms ease-in;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user