main
vue 109 lines 2.48 KB
Raw
1 <template>
2 <n-breadcrumb class="breadcrumb">
3 <n-breadcrumb-item @click="goto({ path: '/' })">
4 <Icon :size="16" :name="HomeIcon" />
5 </n-breadcrumb-item>
6 <TransitionGroup name="anim">
7 <n-breadcrumb-item
8 v-for="(item, index) of items"
9 :key="item.key"
10 :class="`index-${index}`"
11 @click="goto({ path: item.path })"
12 >
13 {{ item.name }}
14 </n-breadcrumb-item>
15 </TransitionGroup>
16 </n-breadcrumb>
17 </template>
18
19 <script lang="ts" setup>
20 import type { RouteLocationNormalizedLoaded } from "vue-router"
21 import type { BreadcrumbItem } from "@/composables/common/useBreadcrumb"
22 import _capitalize from "lodash/capitalize"
23 import _compact from "lodash/compact"
24 import _isEqual from "lodash/isEqual"
25 import _split from "lodash/split"
26 import { NBreadcrumb, NBreadcrumbItem } from "naive-ui"
27 import { onBeforeMount } from "vue"
28 import { useRoute, useRouter } from "vue-router"
29 import Icon from "@/components/common/Icon.vue"
30 import { useBreadcrumb } from "@/composables/common/useBreadcrumb"
31
32 const HomeIcon = "fluent:home-24-regular"
33 const router = useRouter()
34 const route = useRoute()
35 const { items, setItems } = useBreadcrumb()
36
37 function goto(page: Partial<BreadcrumbItem>) {
38 if (page.name && page.name !== route.name) {
39 router.push({ name: page.name })
40 }
41 if (page.path && page.path !== route.path) {
42 router.push({ path: page.path })
43 }
44 }
45
46 function checkRoute(route: RouteLocationNormalizedLoaded) {
47 const newItems: BreadcrumbItem[] = []
48 let pathChunks = _compact(_split(route?.path || "", "/"))
49 if (!pathChunks.length) {
50 pathChunks = _compact(_split(route?.matched?.[0]?.aliasOf?.path || "", "/"))
51 }
52
53 let cumulativePath = ""
54
55 for (const chunk of pathChunks) {
56 const name = _capitalize(chunk)
57 cumulativePath += `/${chunk}`
58
59 newItems.push({
60 name,
61 path: cumulativePath,
62 key: name + cumulativePath
63 })
64 }
65
66 if (route.meta?.title && newItems.length) {
67 const lastItem = newItems.at(-1)
68 if (lastItem) {
69 lastItem.name = route.meta.title
70 }
71 }
72
73 if (!_isEqual(items.value, newItems)) {
74 setItems(newItems)
75 }
76 }
77
78 onBeforeMount(() => {
79 checkRoute(router.currentRoute.value)
80
81 router.beforeResolve(route => {
82 checkRoute(route)
83 })
84 })
85 </script>
86
87 <style lang="scss" scoped>
88 .breadcrumb {
89 .anim-move,
90 .anim-enter-active {
91 transition: all 0.5s var(--bezier-ease);
92
93 @for $i from 0 through 10 {
94 &.index-#{$i} {
95 transition-delay: $i * 0.1s;
96 }
97 }
98 }
99
100 .anim-leave-active {
101 display: none;
102 }
103
104 .anim-enter-from {
105 opacity: 0;
106 transform: translateX(-5px);
107 }
108 }
109 </style>