第一种(router新建一个文件夹)
index.js(这里个人中心(tabs)没有路由,里面有子路由)
// 引入路由
import { createRouter, createWebHistory } from 'vue-router'
// 引入仓库
import { useUserStore } from '@/stores'
// 创建路由
const router = createRouter({
// 路由模式、基础路径
history: createWebHistory(import.meta.env.BASE_URL),
// 路由规则
routes: [
{ path: '/login', component: () => import('@/views/login/LoginPage.vue') }, // 登录页,一级路由
{
path: '/', //登录成功默认跳转的页面,一级路由
component: () => import('@/views/layout/LayoutContainer.vue'),
redirect: '/article/manage', //路由重定向
// 子路由
children: [
{
// 文章管理页面路由
path: '/article/manage',
component: () => import('@/views/article/ArticleManage.vue')
},
// 文章分类页面路由
{
path: '/article/channel',
component: () => import('@/views/article/ArticleChannel.vue')
},
// 个人中心基本资料路由
{
path: '/user/profile',
component: () => import('@/views/user/UserProfile.vue')
},
// 个人中心更换头像路由
{
path: '/user/avatar',
component: () => import('@/views/user/UserAvatar.vue')
},
// 个人中心重置密码路由
{
path: '/user/password',
component: () => import('@/views/user/UserPassword.vue')
}
]
}
]
})
// 登录访问拦截
router.beforeEach((to) => {
// 如果没有token,且返回的是非登录页,拦截到登录。其它情况正常放行
const useStore = useUserStore()
if (!useStore.token && to.path !== '/login') return '/login'
return true
})
export default router
第二种(router新建两个文件,这种方式可以动态渲染,需要用递归组件动态渲染)
index.ts
//通过vue-router插件实现模板路由配置
import { createRouter, createWebHashHistory } from 'vue-router'
import { constantRoute } from './routes'
//创建路由器
const router = createRouter({
//路由模式hash
history: createWebHashHistory(),
routes: constantRoute,
//滚动行为
scrollBehavior() {
return {
left: 0,
top: 0,
}
},
})
export default router
routes.ts(权限管理、商品管理有路由且也有子路由
//路由规则
export const constantRoute = [
// 登录页,一级路由
{
path: '/login',
component: () => import('@/views/login/index.vue'),
name: 'login',
meta: {
title: '登录', //菜单标题
hidden: true, //代表路由标题在菜单中是否隐藏 true:隐藏 false:不隐藏
icon: 'Promotion', //菜单文字左侧的图标,支持element-plus全部图标
},
},
{
//登录成功以后展示数据的路由,一级路由
path: '/',
component: () => import('@/layout/index.vue'),
name: 'layout',
// 路由元信息
meta: {
title: '',
hidden: false,
icon: '',
},
redirect: '/home', //路由重定向
// 子路由,二级路由
children: [
{
path: '/home',
component: () => import('@/views/home/index.vue'),
meta: {
title: '首页',
hidden: false,
icon: 'HomeFilled',
},
},
],
},
//404路由,一级路由
{
path: '/404',
component: () => import('@/views/404/index.vue'),
name: '404',
meta: {
title: '404',
hidden: true,
icon: 'DocumentDelete',
},
},
// 数据大屏,一级路由
{
path: '/screen',
component: () => import('@/views/screen/index.vue'),
name: 'Screen',
meta: {
hidden: false,
title: '数据大屏',
icon: 'Platform',
},
},
// 权限管理,一级路由,用不上,需要里面的二级路由展示
{
path: '/acl',
component: () => import('@/layout/index.vue'),
name: 'Acl',
meta: {
title: '权限管理',
hidden: false,
icon: 'Lock',
},
redirect: '/acl/user', //路由重定向
//子路由,二级路由
children: [
{
path: '/acl/user',
component: () => import('@/views/acl/user/index.vue'),
name: 'Acl',
meta: {
title: '用户管理',
hidden: false,
icon: 'User',
},
},
{
path: '/acl/role',
component: () => import('@/views/acl/role/index.vue'),
name: 'Role',
meta: {
title: '角色管理',
hidden: false,
icon: 'UserFilled',
},
},
{
path: '/acl/permission',
component: () => import('@/views/acl/permission/index.vue'),
name: 'Permissionl',
meta: {
title: '菜单管理',
hidden: false,
icon: 'Monitor',
},
},
],
},
// 商品管理,一级路由,用不上,需要里面的二级路由展示
{
path: '/product',
component: () => import('@/layout/index.vue'),
name: 'Product',
meta: {
title: '商品管理',
icon: 'Goods',
hidden: false,
},
redirect: '/product/trademark', //路由重定向
//子路由,二级路由
children: [
{
path: '/product/trademark',
component: () => import('@/views/product/trademark/index.vue'),
name: 'Trademark',
meta: {
title: '品牌管理',
icon: 'ShoppingCartFull',
},
},
{
path: '/product/attr',
component: () => import('@/views/product/attr/index.vue'),
name: 'Attr',
meta: {
title: '属性管理',
icon: 'ChromeFilled',
},
},
{
path: '/product/spu',
component: () => import('@/views/product/spu/index.vue'),
name: 'Spu',
meta: {
title: 'spu管理',
icon: 'Calendar',
},
},
{
path: '/product/sku',
component: () => import('@/views/product/sku/index.vue'),
name: 'Sku',
meta: {
title: 'sku管理',
icon: 'Orange',
},
},
],
},
]
....路由鉴权,新建一个文件夹(里面用到了路由守卫,导航条nprogress)
//第一个问题:任意路由切换实现进度条业务 ---nprogress
//第二个问题:路由鉴权(路由组件访问权限的设置)
//全部路由组件:登录|404|任意路由|首页|数据大屏|权限管理(三个子路由)|商品管理(四个子路由)
//用户未登录:可以访问login,其余六个路由不能访问(指向login)
//用户登录成功:不可以访问login[指向首页],其余的路由可以访问
//路由鉴权:鉴权,项目当中路由能不能被的权限的设置(某一个路由什么条件下可以访问、什么条件下不可以访问)
import router from '@/router';
import setting from './setting';
import nprogress from 'nprogress';
//引入进度条样式
import "nprogress/nprogress.css";
nprogress.configure({ showSpinner: false });
//获取用户相关的小仓库内部token数据,去判断用户是否登录成功
import useUserStore from './store/modules/user';
import pinia from './store';
let userStore = useUserStore(pinia);
//全局守卫:项目当中任意路由切换都会触发的钩子
//全局前置守卫
router.beforeEach(async (to: any, from: any, next: any) => {
document.title = `${setting.title} - ${to.meta.title}`
//to:你将要访问那个路由
//from:你从来个路由而来
//next:路由的放行函数
nprogress.start();
//获取token,去判断用户登录、还是未登录
let token = userStore.token;
//获取用户名字
let username = userStore.username;
//用户登录判断
if (token) {
//登录成功,访问login,不能访问,指向首页
if (to.path == '/login') {
next({ path: '/' })
} else {
//登录成功访问其余六个路由(登录排除)
//有用户信息
if (username) {
//放行
next();
} else {
//如果没有用户信息,在守卫这里发请求获取到了用户信息再放行
try {
//获取用户信息
await userStore.userInfo();
//放行
//万一:刷新的时候是异步路由,有可能获取到用户信息、异步路由还没有加载完毕,出现空白的效果
next({...to});
} catch (error) {
//token过期:获取不到用户信息了
//用户手动修改本地存储token
//退出登录->用户相关的数据清空
await userStore.userLogout();
next({ path: '/login', query: { redirect: to.path } })
}
}
}
} else {
//用户未登录判断
if (to.path == '/login') {
next();
} else {
next({ path: '/login', query: { redirect: to.path } });
}
}
})
//全局后置守卫
router.afterEach((to: any, from: any) => {
nprogress.done();
});
//第一个问题:任意路由切换实现进度条业务 ---nprogress
//第二个问题:路由鉴权(路由组件访问权限的设置)
//全部路由组件:登录|404|任意路由|首页|数据大屏|权限管理(三个子路由)|商品管理(四个子路由)
//用户未登录:可以访问login,其余六个路由不能访问(指向login)
//用户登录成功:不可以访问login[指向首页],其余的路由可以访问