mirror of
https://github.com/continew-org/continew-admin-ui.git
synced 2025-10-30 00:58:37 +08:00
refactor: 路由多级缓存调整为扁平化方案
This commit is contained in:
@@ -13,19 +13,32 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { RouteLocationMatched } from 'vue-router'
|
import type { RouteLocationMatched } from 'vue-router'
|
||||||
|
import { useRouteStore } from '@/stores'
|
||||||
|
import { findTree } from 'xe-utils'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const { routes } = useRouteStore()
|
||||||
|
|
||||||
|
let home: RouteLocationMatched | null = null
|
||||||
|
const getHome = () => {
|
||||||
|
if (!home) {
|
||||||
|
const cloneRoutes = JSON.parse(JSON.stringify(routes)) as RouteLocationMatched[]
|
||||||
|
const obj = findTree(cloneRoutes, (i) => i.path === '/home')
|
||||||
|
home = obj.item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const breadcrumbList = ref<RouteLocationMatched[]>([])
|
const breadcrumbList = ref<RouteLocationMatched[]>([])
|
||||||
function getBreadcrumbList() {
|
function getBreadcrumbList() {
|
||||||
// 只显示有title标题的
|
getHome()
|
||||||
const matched = route.matched.filter((item) => item.meta && item.meta.title)
|
const cloneRoutes = JSON.parse(JSON.stringify(routes)) as RouteLocationMatched[]
|
||||||
const first = matched[0]
|
const obj = findTree(cloneRoutes, (i) => i.path === route.path)
|
||||||
if (!isHome(first)) {
|
// 获取当前节点的所有上级节点集合,包含当前节点
|
||||||
matched.unshift({ path: '/', meta: { title: '首页' } } as RouteLocationMatched)
|
const arr = obj.nodes.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
||||||
|
if (home) {
|
||||||
|
breadcrumbList.value = [home, ...arr]
|
||||||
}
|
}
|
||||||
breadcrumbList.value = matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
|
||||||
}
|
}
|
||||||
getBreadcrumbList()
|
getBreadcrumbList()
|
||||||
|
|
||||||
@@ -34,13 +47,6 @@ watchEffect(() => {
|
|||||||
getBreadcrumbList()
|
getBreadcrumbList()
|
||||||
})
|
})
|
||||||
|
|
||||||
// 判断是否为首页
|
|
||||||
function isHome(route: RouteLocationMatched) {
|
|
||||||
const name = (route?.name as string) || ''
|
|
||||||
if (!name) return false
|
|
||||||
return name.trim() === 'Home'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 路由跳转
|
// 路由跳转
|
||||||
function handleLink(item: RouteLocationMatched) {
|
function handleLink(item: RouteLocationMatched) {
|
||||||
const { redirect, path } = item
|
const { redirect, path } = item
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-layout class="main">
|
<a-layout class="main">
|
||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
<transition :name="transitionName(route)" mode="out-in" appear>
|
<transition :name="appStore.transitionName" mode="out-in" appear>
|
||||||
<keep-alive :include="(tabsStore.cacheList as string[])">
|
<keep-alive :include="(tabsStore.cacheList as string[])">
|
||||||
<component :is="Component" :key="route.matched?.[1]?.path" />
|
<component :is="Component" :key="route.path" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
@@ -11,22 +11,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
|
||||||
import { useAppStore, useTabsStore } from '@/stores'
|
import { useAppStore, useTabsStore } from '@/stores'
|
||||||
|
|
||||||
defineOptions({ name: 'Main' })
|
defineOptions({ name: 'Main' })
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const tabsStore = useTabsStore()
|
const tabsStore = useTabsStore()
|
||||||
|
|
||||||
// 过渡动画
|
|
||||||
const transitionName = computed(() => {
|
|
||||||
return function (route: RouteLocationNormalizedLoaded) {
|
|
||||||
if (route?.matched?.[1]?.meta?.animation === false) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
return appStore.transitionName
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import { ref, toRaw } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import type { RouteRecordRaw } from 'vue-router'
|
import type { RouteRecordRaw } from 'vue-router'
|
||||||
import { constantRoutes } from '@/router'
|
import { constantRoutes } from '@/router'
|
||||||
import Layout from '@/layout/index.vue'
|
|
||||||
import ParentView from '@/components/ParentView/index.vue'
|
import ParentView from '@/components/ParentView/index.vue'
|
||||||
import { getUserRoute, type RouteItem } from '@/apis'
|
import { getUserRoute, type RouteItem } from '@/apis'
|
||||||
import { mapTree } from 'xe-utils'
|
import { mapTree, toTreeArray } from 'xe-utils'
|
||||||
|
import { cloneDeep, omit } from 'lodash-es'
|
||||||
import { transformPathToName } from '@/utils'
|
import { transformPathToName } from '@/utils'
|
||||||
|
|
||||||
|
const Layout = () => import('@/layout/index.vue')
|
||||||
|
|
||||||
// 匹配views里面所有的.vue文件
|
// 匹配views里面所有的.vue文件
|
||||||
const modules = import.meta.glob('@/views/**/*.vue')
|
const modules = import.meta.glob('@/views/**/*.vue')
|
||||||
|
|
||||||
@@ -64,6 +66,28 @@ const formatAsyncRoutes = (menus: RouteItem[]) => {
|
|||||||
return routes as RouteRecordRaw[]
|
return routes as RouteRecordRaw[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 判断路由层级是否大于 2 */
|
||||||
|
export const isMultipleRoute = (route: RouteRecordRaw) => {
|
||||||
|
const children = route.children
|
||||||
|
if (children?.length) {
|
||||||
|
// 只要有一个子路由的 children 长度大于 0,就说明是三级及其以上路由
|
||||||
|
return children.some((child) => child.children?.length)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 路由降级(把三级及其以上的路由转化为二级路由) */
|
||||||
|
export const flatMultiLevelRoutes = (routes: RouteRecordRaw[]) => {
|
||||||
|
const cloneRoutes = cloneDeep(routes)
|
||||||
|
cloneRoutes.forEach((route) => {
|
||||||
|
if (isMultipleRoute(route)) {
|
||||||
|
const flatRoutes = toTreeArray(route.children)
|
||||||
|
route.children = flatRoutes.map((i) => omit(i, 'children')) as RouteRecordRaw[]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return cloneRoutes
|
||||||
|
}
|
||||||
|
|
||||||
const storeSetup = () => {
|
const storeSetup = () => {
|
||||||
// 所有路由(常驻路由 + 动态路由)
|
// 所有路由(常驻路由 + 动态路由)
|
||||||
const routes = ref<RouteRecordRaw[]>([])
|
const routes = ref<RouteRecordRaw[]>([])
|
||||||
@@ -74,7 +98,6 @@ const storeSetup = () => {
|
|||||||
const setRoutes = (data: RouteRecordRaw[]) => {
|
const setRoutes = (data: RouteRecordRaw[]) => {
|
||||||
routes.value = constantRoutes.concat(data)
|
routes.value = constantRoutes.concat(data)
|
||||||
asyncRoutes.value = data
|
asyncRoutes.value = data
|
||||||
console.log('路由', toRaw(routes.value))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成路由
|
// 生成路由
|
||||||
@@ -84,7 +107,9 @@ const storeSetup = () => {
|
|||||||
getUserRoute().then((res) => {
|
getUserRoute().then((res) => {
|
||||||
const asyncRoutes = formatAsyncRoutes(res.data)
|
const asyncRoutes = formatAsyncRoutes(res.data)
|
||||||
setRoutes(asyncRoutes)
|
setRoutes(asyncRoutes)
|
||||||
resolve(asyncRoutes)
|
const cloneRoutes = cloneDeep(asyncRoutes)
|
||||||
|
const flatRoutes = flatMultiLevelRoutes(cloneRoutes as RouteRecordRaw[])
|
||||||
|
resolve(flatRoutes)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ const storeSetup = () => {
|
|||||||
const cacheList = ref<RouteRecordName[]>([]) // keep-alive缓存的数组, 元素是组件名
|
const cacheList = ref<RouteRecordName[]>([]) // keep-alive缓存的数组, 元素是组件名
|
||||||
|
|
||||||
// 添加一个页签, 如果当前路由已经打开, 则不再重复添加
|
// 添加一个页签, 如果当前路由已经打开, 则不再重复添加
|
||||||
const addTagItem = (item: RouteRecordRaw) => {
|
const addTagItem = (route: RouteRecordRaw) => {
|
||||||
|
const item = JSON.parse(JSON.stringify(route))
|
||||||
if (tagList.value.some((i) => i.path === item.path)) return
|
if (tagList.value.some((i) => i.path === item.path)) return
|
||||||
if (item.meta?.showInTabs ?? true) {
|
if (item.meta?.showInTabs ?? true) {
|
||||||
tagList.value.push(item)
|
tagList.value.push(item)
|
||||||
@@ -35,7 +36,7 @@ const storeSetup = () => {
|
|||||||
const arr: RouteRecordRaw[] = []
|
const arr: RouteRecordRaw[] = []
|
||||||
_XEUtils_.eachTree(routeStore.routes, (item) => {
|
_XEUtils_.eachTree(routeStore.routes, (item) => {
|
||||||
if (item.meta?.affix ?? false) {
|
if (item.meta?.affix ?? false) {
|
||||||
arr.push(item)
|
arr.push(JSON.parse(JSON.stringify(item)))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
tagList.value = arr
|
tagList.value = arr
|
||||||
|
|||||||
4
src/types/router.d.ts
vendored
4
src/types/router.d.ts
vendored
@@ -11,7 +11,7 @@ declare module 'vue-router' {
|
|||||||
/** 默认false, 设置true的时候该路由不会在侧边栏出现 */
|
/** 默认false, 设置true的时候该路由不会在侧边栏出现 */
|
||||||
hidden?: boolean
|
hidden?: boolean
|
||||||
/** 默认true, 如果设置为false, 则不会在面包屑中显示 */
|
/** 默认true, 如果设置为false, 则不会在面包屑中显示 */
|
||||||
breadcrumb?: false
|
breadcrumb?: boolean
|
||||||
/** 默认true, 如果设置为false, 它则不会显示在Tab栏中 */
|
/** 默认true, 如果设置为false, 它则不会显示在Tab栏中 */
|
||||||
showInTabs?: boolean
|
showInTabs?: boolean
|
||||||
/** 默认false, 如果设置为true, 它则会固定在Tab栏中, 例如首页 */
|
/** 默认false, 如果设置为true, 它则会固定在Tab栏中, 例如首页 */
|
||||||
@@ -39,8 +39,6 @@ declare module 'vue-router' {
|
|||||||
noShowingChildren?: boolean
|
noShowingChildren?: boolean
|
||||||
/** 设置该路由进入的权限, 支持多个权限叠加 */
|
/** 设置该路由进入的权限, 支持多个权限叠加 */
|
||||||
roles?: string[]
|
roles?: string[]
|
||||||
/** 路由切换是否使用动画 */
|
|
||||||
animation?: boolean
|
|
||||||
/** 排序 */
|
/** 排序 */
|
||||||
sort?: number
|
sort?: number
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user