zhou zhou
18 小时以前 46d872c1a5b77aa8799de4a64888a0a24a1422d6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<!-- 面包屑导航 -->
<template>
  <nav class="ml-2.5 max-lg:!hidden" aria-label="breadcrumb">
    <ul class="flex-c h-full">
      <li
        v-for="(item, index) in breadcrumbItems"
        :key="item.path"
        class="box-border flex-c h-7 text-sm leading-7"
      >
        <div
          :class="
            isClickable(item, index)
              ? 'c-p py-1 rounded tad-200 hover:bg-active-color hover:[&_span]:text-g-600'
              : ''
          "
          @click="handleBreadcrumbClick(item, index)"
        >
          <span
            class="block max-w-46 overflow-hidden text-ellipsis whitespace-nowrap px-1.5 text-sm text-g-600 dark:text-g-800"
            >{{ formatMenuTitle(item.meta?.title) }}</span
          >
        </div>
        <div
          v-if="!isLastItem(index) && item.meta?.title"
          class="mx-1 text-sm not-italic text-g-500"
          aria-hidden="true"
        >
          /
        </div>
      </li>
    </ul>
  </nav>
</template>
 
<script setup>
  import { computed } from 'vue'
  import { useRouter, useRoute } from 'vue-router'
  import { formatMenuTitle } from '@/utils/router'
  defineOptions({ name: 'ArtBreadcrumb' })
  const route = useRoute()
  const router = useRouter()
  const breadcrumbItems = computed(() => {
    const { matched } = route
    const matchedLength = matched.length
    if (!matchedLength || isHomeRoute(matched[0])) {
      return []
    }
    const firstRoute = matched[0]
    const isFirstLevel = firstRoute.meta?.isFirstLevel
    const lastIndex = matchedLength - 1
    const currentRoute = matched[lastIndex]
    const currentRouteMeta = currentRoute.meta
    let items = isFirstLevel
      ? [createBreadcrumbItem(currentRoute)]
      : matched.map(createBreadcrumbItem)
    if (items.length > 1 && isWrapperContainer(items[0])) {
      items = items.slice(1)
    }
    if (currentRouteMeta?.isIframe && (items.length === 1 || items.every(isWrapperContainer))) {
      return [createBreadcrumbItem(currentRoute)]
    }
    return items
  })
  const isWrapperContainer = (item) => item.path === '/outside' && !!item.meta?.isIframe
  const createBreadcrumbItem = (route2) => ({
    path: route2.path,
    meta: route2.meta
  })
  const isHomeRoute = (route2) => route2.name === '/'
  const isLastItem = (index) => {
    const itemsLength = breadcrumbItems.value.length
    return index === itemsLength - 1
  }
  const isClickable = (item, index) => item.path !== '/outside' && !isLastItem(index)
  const findFirstValidChild = (route2) =>
    route2.children?.find((child) => !child.redirect && !child.meta?.isHide)
  const buildFullPath = (childPath) => `/${childPath}`.replace('//', '/')
  async function handleBreadcrumbClick(item, index) {
    if (isLastItem(index) || item.path === '/outside') {
      return
    }
    try {
      const routes = router.getRoutes()
      const targetRoute = routes.find((route2) => route2.path === item.path)
      if (!targetRoute?.children?.length) {
        await router.push(item.path)
        return
      }
      const firstValidChild = findFirstValidChild(targetRoute)
      if (firstValidChild) {
        await router.push(buildFullPath(firstValidChild.path))
      } else {
        await router.push(item.path)
      }
    } catch (error) {
      console.error('导航失败:', error)
    }
  }
</script>