feat: 菜单支持a标签右键的所有浏览器行为(在新标签页中、新窗口中打开链接,拖拽到新标签页打开等) (#936)

* feat: 菜单支持a标签右键的所有浏览器行为(在新标签页中、新窗口中打开链接,拖拽到新标签页打开等)

* feat: 修复添加a标签样式问题

* feat: 修复windows下双滚动条问题

* feat: 修复添加a标签样式问题
This commit is contained in:
Banana Energy 2024-03-01 11:38:47 +08:00 committed by GitHub
parent 51809546ed
commit 2b71e8bd54
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 116 additions and 57 deletions

View File

@ -0,0 +1,36 @@
<script setup lang="ts">
import { computed } from "vue";
import { isUrl } from "@pureadmin/utils";
import { menuType } from "@/layout/types";
defineOptions({
name: "LinkItem"
});
const props = defineProps<{
to: menuType;
}>();
const isExternalLink = computed(() => isUrl(props.to.name));
const getLinkProps = (item: menuType) => {
if (isExternalLink.value) {
return {
href: item.name,
target: "_blank",
rel: "noopener"
};
}
return {
to: item
};
};
</script>
<template>
<component
:is="isExternalLink ? 'a' : 'router-link'"
v-bind="getLinkProps(to)"
>
<slot />
</component>
</template>

View File

@ -48,6 +48,7 @@ const { title, getLogo } = useNav();
flex-wrap: nowrap;
align-items: center;
height: 100%;
padding-left: 10px;
img {
display: inline-block;

View File

@ -1,19 +1,28 @@
<script setup lang="ts">
import path from "path";
import { getConfig } from "@/config";
import LinkItem from "./linkItem.vue";
import { menuType } from "../../types";
import extraIcon from "./extraIcon.vue";
import { ReText } from "@/components/ReText";
import { useNav } from "@/layout/hooks/useNav";
import { transformI18n } from "@/plugins/i18n";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { type CSSProperties, type PropType, computed, ref, toRaw } from "vue";
import {
type PropType,
type CSSProperties,
ref,
toRaw,
computed,
useAttrs
} from "vue";
import ArrowUp from "@iconify-icons/ep/arrow-up-bold";
import EpArrowDown from "@iconify-icons/ep/arrow-down-bold";
import ArrowLeft from "@iconify-icons/ep/arrow-left-bold";
import ArrowRight from "@iconify-icons/ep/arrow-right-bold";
const attrs = useAttrs();
const { layout, isCollapse, tooltipEffect, getDivStyle } = useNav();
const props = defineProps({
@ -32,6 +41,7 @@ const props = defineProps({
const getNoDropdownStyle = computed((): CSSProperties => {
return {
width: "100%",
display: "flex",
alignItems: "center"
};
@ -96,61 +106,66 @@ function resolvePath(routePath) {
</script>
<template>
<el-menu-item
<link-item
v-if="
hasOneShowingChild(props.item.children, props.item) &&
(!onlyOneChild.children || onlyOneChild.noShowingChildren)
"
:index="resolvePath(onlyOneChild.path)"
:class="{ 'submenu-title-noDropdown': !isNest }"
:style="getNoDropdownStyle"
:to="item"
>
<div
v-if="toRaw(props.item.meta.icon)"
class="sub-menu-icon"
:style="getSubMenuIconStyle"
<el-menu-item
:index="resolvePath(onlyOneChild.path)"
:class="{ 'submenu-title-noDropdown': !isNest }"
:style="getNoDropdownStyle"
v-bind="attrs"
>
<component
:is="
useRenderIcon(
toRaw(onlyOneChild.meta.icon) ||
(props.item.meta && toRaw(props.item.meta.icon))
)
"
/>
</div>
<el-text
v-if="
(!props.item?.meta.icon &&
isCollapse &&
layout === 'vertical' &&
props.item?.pathList?.length === 1) ||
(!onlyOneChild.meta.icon &&
isCollapse &&
layout === 'mix' &&
props.item?.pathList?.length === 2)
"
truncated
class="!px-4 !text-inherit"
>
{{ transformI18n(onlyOneChild.meta.title) }}
</el-text>
<template #title>
<div :style="getDivStyle">
<ReText
:tippyProps="{
offset: [0, -10],
theme: tooltipEffect
}"
class="!text-inherit"
>
{{ transformI18n(onlyOneChild.meta.title) }}
</ReText>
<extraIcon :extraIcon="onlyOneChild.meta.extraIcon" />
<div
v-if="toRaw(props.item.meta.icon)"
class="sub-menu-icon"
:style="getSubMenuIconStyle"
>
<component
:is="
useRenderIcon(
toRaw(onlyOneChild.meta.icon) ||
(props.item.meta && toRaw(props.item.meta.icon))
)
"
/>
</div>
</template>
</el-menu-item>
<el-text
v-if="
(!props.item?.meta.icon &&
isCollapse &&
layout === 'vertical' &&
props.item?.pathList?.length === 1) ||
(!onlyOneChild.meta.icon &&
isCollapse &&
layout === 'mix' &&
props.item?.pathList?.length === 2)
"
truncated
class="!px-4 !text-inherit"
>
{{ transformI18n(onlyOneChild.meta.title) }}
</el-text>
<template #title>
<div :style="getDivStyle">
<ReText
:tippyProps="{
offset: [0, -10],
theme: tooltipEffect
}"
class="!text-inherit"
>
{{ transformI18n(onlyOneChild.meta.title) }}
</ReText>
<extraIcon :extraIcon="onlyOneChild.meta.extraIcon" />
</div>
</template>
</el-menu-item>
</link-item>
<el-sub-menu
v-else
ref="subMenu"

View File

@ -62,6 +62,7 @@ export interface setType {
export type menuType = {
id?: number;
name?: string;
path?: string;
noShowingChildren?: boolean;
children?: menuType[];

View File

@ -14,6 +14,11 @@
}
}
/* 修复 windows 下双滚动条问题 https://github.com/pure-admin/vue-pure-admin/pull/936#issuecomment-1968125992 */
.el-popper.pure-scrollbar {
overflow: hidden;
}
/* popper menu 超出内容区可滚动 */
.pure-scrollbar {
max-height: calc(100vh - calc(50px * 2.5));
@ -130,11 +135,9 @@
}
a {
display: inline-block;
display: flex;
flex-wrap: wrap;
width: 100%;
padding-left: 10px;
}
.el-menu {
@ -331,9 +334,18 @@
margin-top: 0;
}
/* 无子菜单时激活 border-bottom */
a > .is-active.submenu-title-noDropdown {
border-bottom: 2px solid var(--el-menu-active-color);
}
.el-menu--popup {
background-color: $subMenuBg !important;
a > .is-active.submenu-title-noDropdown {
border-bottom: none;
}
.el-menu-item {
color: $menuText;
background-color: $subMenuBg;
@ -348,12 +360,6 @@
}
}
/* 无子菜单时激活 border-bottom */
.router-link-exact-active > .submenu-title-noDropdown {
height: 60px;
border-bottom: 2px solid var(--el-menu-active-color);
}
/* 子菜单中还有子菜单 */
.el-menu .el-sub-menu__title {
min-width: $sideBarWidth !important;