接口返回数据格式:
1、路由文件配置router.ts
import { RouteRecordRaw, createRouter, createWebHistory } from 'vue-router';
import { App } from 'vue'
import { createRouterGuards } from "./router-guards"
export const indexChildRoutes = [
{
path: '/home',
name: 'Home',
hidden: false,
meta: { title: '首页', hidden: false, icon: 'icon-ic_menu_home' },
component: () => import(/* @vite-ignore */`../views/home/index`)
}
]
export const routes: RouteRecordRaw[] = [
{
path: '/login',
name: 'Login',
component: () => import("../views/LoginIndex.vue")
},
{
path: '/',
name: 'sysjindex',
component: () => import('../layouts/BasicLayoutIndex.vue'),
redirect: '/home',
children: []
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export function setupRouter(app: App) {
createRouterGuards(router, routes)
app.use(router)
}
export default router;
// main中使用
// import router, { setupRouter } from './router';
// // 挂载路由
// setupRouter(app)
// 路由准备就绪后挂载APP实例
// router.isReady().then(() => app.mount('#app'))
2、./router-guards 设置动态路由
import { Router } from "vue-router"
import store from "../store"
const whiteList = ['/login']
// const store = useStore()
export function createRouterGuards(router: Router, routes: any) {
router.beforeEach((to, form, next) => {
let token = localStorage.getItem("token")
if (token) {
// console.log(store.state.user.routes.length)
if (!store.state.user.routes.length) {
// 拉取useinfo信息
store.dispatch('GetInfo')
store.dispatch("GenerateRoutes").then((res) => {
const layout = routes.find((item: any) => item.name == 'sysjindex')!
layout.children = [...res]
router.addRoute(layout)
// res.map((item: any) => router.addRoute("sysjindex", item))
next({ ...to, replace: true })
})
} else {
next()
}
} else {
// 没有token
if (whiteList.indexOf(to.path) !== -1) {
// 在免登录白名单,直接进入
next()
} else {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
}
}
})
}
2.1、store获取处理getRoutes
// actions
const actions = {
// 生成路由
GenerateRoutes({ commit }: ActionContext<any, any>) {
return new Promise(resolve => {
// 向后端请求路由数据
getRouters().then(res => {
let accessedRoutes = filterAsnycRouter(res.data);
accessedRoutes = indexChildRoutes.concat(accessedRoutes)
// accessedRoutes.push({ path: "*", redirect: "/404", hidden: true });
commit("SET_ROUTES", accessedRoutes);
// console.log(accessedRoutes)
resolve(accessedRoutes);
});
});
},
...
}
// mutations
const mutations = {
SET_ROUTES: (state: State, routes: Array<any>) => {
state.routes = routes;
},
中filterAsnycRouter,在main.ts文件平级目录下新建importRoutercom.ts文件,为了处理。Glob 模式会被当成导入标识符:必须是相对路径(以
./开头)或绝对路径(以/开头,相对于项目根目录解析)。
2.2、importRoutercom.ts
import 'vite/dynamic-import-polyfill';
export function filterAsnycRouter(asyncRouterMap: any) {
return asyncRouterMap.filter((route: any) => {
if (route.component == 'Layout') {
route.component = () => import('./layouts/BlankIndex.vue')
} else {
route.path = `${route.path}`
route.component = resolveComponent(route.component);
}
if (route.children != null && route.children && route.children.length) {
route.children = filterAsnycRouter(route.children);
}
return true;
})
}
const pages = import.meta.globEager('./views/**/*.vue');
// 以 `./` 开头)或绝对路径(以 `/` 开头
const resolveComponent = (name: any) => {
const importPage = pages[`./views/${name}.vue`];
if (!importPage) {
throw new Error(`Unknown page ${name}. Is it located under Pages with a .vue extension?`);
}
// return importPage().then(module => module.default);
return importPage.default
}
处理在build下,unknown variable dynamic import:报错
参照代码:owenconti.com/posts/repla…
3.上述解决添加keep-alive缓存不生效问题
用在其【一个】【直属】的子组件被切换。KeepAlive包裹仅有一个组件且是单层的路由
在 basicLayoutIndex 中<RouterView ... />修改为添加
<BlankIndex :isRouterAlive="isRouterAlive"/>组件
import {provide, ref} from "vue";
const isRouterAlive = ref(true);
// 页面刷新按钮
provide("reload", () => {
isRouterAlive.value = false;
nextTick(() => {
isRouterAlive.value = true;
});
});
BlankIndex.vue
<script setup lang="ts">
import {computed} from "vue"
import {useUserStore} from "@/store/user.ts";
const props = defineProps({
isRouterAlive: {
type: Boolean,
default: true
},
});
const store = useUserStore();
// 顶部缓存的tab 标签页面
const tabsCacheList = computed(() => {
let aaa:any = []
store.tabsList.forEach((item:any) => {
if(item.meta.isCache == '0') {
aaa.push(item.name)
}
})
return aaa
});
</script>
<template>
<RouterView v-slot="{ Component,route }" v-if="props.isRouterAlive">
<KeepAlive :include="tabsCacheList">
<component :is="Component" :key="route.fullPath"/>
</KeepAlive>
</RouterView>
</template>
router.js修改
export const indexChildRoutes = [
{
path: '',
component: "Layout",
menuType: 'C', // C菜单,M 目录
redirect: '/home',
meta: { title: '首页', hidden: false, icon: 'icon-ic_menu_home' },
children: [
{
path: '/home',
component: () => import(/* @vite-ignore */`../views/home.vue`),
name: 'home',
// isCache 0缓存
meta: { title: '首页', hidden: false, icon: 'icon-ic_menu_home', isCache: '1' }
}
]
}
]
importRoutercom修改,调整Layout基类,设置路由 name 从 path 中取,动态设置组件 name 为路由的 name
export function filterAsnycRouter(asyncRouterMap: any) {
return asyncRouterMap.filter((route: any) => {
if (route.component == 'Layout') {
route.component = () => import('./layouts/BasicLayoutIndex.vue')
} else if (route.component === 'ParentView') {
route.component = () => import('./components/ParentView/index.vue')
} else {
// route.path = `/${route.component}`
if(route.name !== 'home') {
let name = route.path.split('/').pop()
route.name = name.charAt(0).toUpperCase() + name.slice(1)
route.path = `${route.path}`
route.component = resolveComponent(route.component,route.name);
}
}
if (route.children != null && route.children && route.children.length) {
route.children = filterAsnycRouter(route.children);
}
return true;
})
}
const pages = import.meta.glob('./views/**/*.vue');
const resolveComponent = (name: any,routername:any) => {
let importPage = null
for (let key of Object.keys(pages)) {
if (key.indexOf(name) !== -1) {
importPage = pages[key]
break;
}
}
if (!importPage) throw new Error(`${name} 组件文件不存在!`)
//重新构造组件,调整组件name
return importPage().then(comp => ({
...comp.default,
name: routername,
}))
// return importPage
}
store 中修改GenerateRoutesaction,追加 home 到动态处理路由组件中res.data.unshift(indexChildRoutes[0])
// 生成路由
GenerateRoutes() {
return new Promise((resolve) => {
// 向后端请求路由数据
getRouters().then((res) => {
if (!res) return;
res.data.unshift(indexChildRoutes[0])
let accessedRoutes = filterAsnycRouter(res.data);
this.routes = accessedRoutes;
resolve(accessedRoutes);
});
});
},