vue-vben-admin/src/layouts/default/header/components/Breadcrumb.vue

210 lines
5.9 KiB
Vue
Raw Normal View History

2020-12-03 21:49:32 +08:00
<template>
2020-12-15 00:13:23 +08:00
<div :class="[prefixCls, `${prefixCls}--${theme}`]">
2020-12-03 21:49:32 +08:00
<a-breadcrumb :routes="routes">
<template #itemRender="{ route, routes, paths }">
<Icon :icon="getIcon(route)" v-if="getShowBreadCrumbIcon && getIcon(route)" />
<span v-if="!hasRedirect(routes, route)">
{{ t(route.name || route.meta.title) }}
2020-12-03 21:49:32 +08:00
</span>
<router-link v-else to="" @click="handleClick(route, paths, $event)">
{{ t(route.name || route.meta.title) }}
2020-12-03 21:49:32 +08:00
</router-link>
</template>
</a-breadcrumb>
</div>
</template>
<script lang="ts">
2021-01-18 23:37:36 +08:00
import type { RouteLocationMatched } from 'vue-router';
import type { Menu } from '/@/router/types';
2021-01-18 23:37:36 +08:00
import { defineComponent, ref, watchEffect } from 'vue';
2020-12-03 21:49:32 +08:00
import { Breadcrumb } from 'ant-design-vue';
2020-12-03 21:49:32 +08:00
import Icon from '/@/components/Icon';
2020-12-15 00:13:23 +08:00
import { useDesign } from '/@/hooks/web/useDesign';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { useGo } from '/@/hooks/web/usePage';
import { useI18n } from '/@/hooks/web/useI18n';
import { useRouter } from 'vue-router';
2020-12-15 00:13:23 +08:00
import { propTypes } from '/@/utils/propTypes';
import { isString } from '/@/utils/is';
import { filter } from '/@/utils/helper/treeHelper';
import { getMenus } from '/@/router/menus';
2020-12-15 00:13:23 +08:00
import { REDIRECT_NAME } from '/@/router/constant';
import { getAllParentPath } from '/@/router/helper/menuHelper';
2020-12-03 21:49:32 +08:00
export default defineComponent({
name: 'LayoutBreadcrumb',
2021-01-28 23:28:50 +08:00
components: { Icon, [Breadcrumb.name]: Breadcrumb },
2020-12-03 21:49:32 +08:00
props: {
2020-12-15 00:13:23 +08:00
theme: propTypes.oneOf(['dark', 'light']),
2020-12-03 21:49:32 +08:00
},
setup() {
const routes = ref<RouteLocationMatched[]>([]);
const { currentRoute } = useRouter();
2020-12-15 00:13:23 +08:00
const { prefixCls } = useDesign('layout-breadcrumb');
const { getShowBreadCrumbIcon } = useRootSetting();
2020-12-03 21:49:32 +08:00
const { t } = useI18n();
watchEffect(async () => {
if (currentRoute.value.name === REDIRECT_NAME) return;
const menus = await getMenus();
const routeMatched = currentRoute.value.matched;
const cur = routeMatched?.[routeMatched.length - 1];
let path = currentRoute.value.path;
if (cur && cur?.meta?.currentActiveMenu) {
path = cur.meta.currentActiveMenu as string;
}
const parent = getAllParentPath(menus, path);
const filterMenus = menus.filter((item) => item.path === parent[0]);
const matched = getMatched(filterMenus, parent) as any;
2020-12-03 21:49:32 +08:00
if (!matched || matched.length === 0) return;
const breadcrumbList = filterItem(matched);
2020-12-03 21:49:32 +08:00
if (currentRoute.value.meta?.currentActiveMenu) {
breadcrumbList.push(({
...currentRoute.value,
name: currentRoute.value.meta?.title || currentRoute.value.name,
} as unknown) as RouteLocationMatched);
}
routes.value = breadcrumbList;
2020-12-03 21:49:32 +08:00
});
function getMatched(menus: Menu[], parent: string[]) {
const metched: Menu[] = [];
menus.forEach((item) => {
if (parent.includes(item.path)) {
metched.push({
...item,
name: item.meta?.title || item.name,
});
}
if (item.children?.length) {
metched.push(...getMatched(item.children, parent));
}
});
return metched;
}
function filterItem(list: RouteLocationMatched[]) {
let resultList = filter(list, (item) => {
const { meta, name } = item;
if (!meta) {
return !!name;
}
const { title, hideBreadcrumb, hideMenu } = meta;
if (!title || hideBreadcrumb || hideMenu) {
return false;
}
return true;
}).filter((item) => !item.meta?.hideBreadcrumb || !item.meta?.hideMenu);
return resultList;
}
function handleClick(route: RouteLocationMatched, paths: string[], e: Event) {
e?.preventDefault();
const { children, redirect, meta } = route;
if (children?.length && !redirect) {
e?.stopPropagation();
return;
}
if (meta?.carryParam) {
return;
}
const go = useGo();
if (redirect && isString(redirect)) {
go(redirect);
} else {
let goPath = '';
if (paths.length === 1) {
goPath = paths[0];
} else {
const ps = paths.slice(1);
const lastPath = ps.pop() || '';
goPath = `${lastPath}`;
}
goPath = /^\//.test(goPath) ? goPath : `/${goPath}`;
go(goPath);
}
}
function hasRedirect(routes: RouteLocationMatched[], route: RouteLocationMatched) {
if (routes.indexOf(route) === routes.length - 1) {
return false;
}
return true;
}
function getIcon(route) {
return route.icon || route.meta?.icon;
}
return { routes, t, prefixCls, getIcon, getShowBreadCrumbIcon, handleClick, hasRedirect };
2020-12-03 21:49:32 +08:00
},
});
</script>
2020-12-15 00:13:23 +08:00
<style lang="less">
@prefix-cls: ~'@{namespace}-layout-breadcrumb';
.@{prefix-cls} {
display: flex;
padding: 0 8px;
align-items: center;
.ant-breadcrumb-link {
.anticon {
margin-right: 4px;
margin-bottom: 2px;
}
}
&--light {
.ant-breadcrumb-link {
color: @breadcrumb-item-normal-color;
a {
2020-12-21 23:38:16 +08:00
color: rgba(0, 0, 0, 0.65);
2020-12-15 00:13:23 +08:00
&:hover {
color: @primary-color;
}
}
}
.ant-breadcrumb-separator {
color: @breadcrumb-item-normal-color;
}
}
&--dark {
.ant-breadcrumb-link {
color: rgba(255, 255, 255, 0.6);
a {
color: rgba(255, 255, 255, 0.8);
&:hover {
color: @white;
}
}
}
.ant-breadcrumb-separator,
.anticon {
color: rgba(255, 255, 255, 0.8);
}
}
}
</style>