入口函数:src/App.vue
<template>
<ConfigProvider :locale="getAntdLocale">
<AppProvider>
<RouterView />
</AppProvider>
</ConfigProvider>
</template>
ConfigProvider:全局化配置,为组件提供统一的全局化配置。可以用来设置Antd的全局配置,如时区、主题等,在一个地方设置,不用每个组件都进行配置。
AppProvider:该组件在src/components/Application/index.ts中引入,使用工具类(src/utils/index.ts)的withInstall方法。该方法是对install方法的封装(在vue中使用一个组件会使用app.use()将其挂载到全局,使用app.use()需要每个组件都提供一个install方法,因此将其二次封装成withInstall方法)。
RouterView:是vue的一个组件,用于渲染与当前路由匹配的视图,当用户导航到不同页面时,RouterView组件会显示与当前路由对应的组件(路由内容在main.ts文件中)。
路由注册:src/main.ts
......
import { router, setupRouter } from '/@/router';
import { setupRouterGuard } from '/@/router/guard';
......
}
async function bootstrap() {
// 创建应用实例
const app = createApp(App);
......
// 配置路由
setupRouter(app);
// 路由保护
setupRouterGuard(router);
......
// 挂载应用
app.mount('#app', true);
}
bootstrap();
在main.ts中使用setupRouter()方法进行路由配置,该方法位于src/router/index.ts,该方法使用app.use()将路由(router)挂载到实例上。
router:
export const router = createRouter({
history: createWebHistory(import.meta.env.VITE_PUBLIC_PATH),
routes: basicRoutes as unknown as RouteRecordRaw[],
strict: true,
scrollBehavior: () => ({ left: 0, top: 0 }),
});
history:指定路由的 history 模式,目前支持 createWebHistory()
和 createWebHashHistory()
模式
routes:定义路由规则的数组,每一个路由规则都是一个对象,包含path、name、component和meta 等属性。
strict:是否应该禁止尾部斜杠。默认为假
scrollBehavior:滚动行为。{left:0,top:0}:始终滚动到顶部靠左。【Vue Router】015-滚动行为*_createrouter scrollbehavior_訾博ZiBo的博客-CSDN博客
import.meta.env.VITE_PUBLIC_PATH:是读取.env的VITE_PUBLIC_PATH值。
basicRoutes as unknown as RouteRecordRaw[]:添加到路由的初始路由列表。
as unknown as 是用来代替 as any的
basicRoutes 是src/router/routes/index.ts对外暴露的路由
RouteRecordRaw[]路由数组
basicRoutes:src/router/routes/index.ts
import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic';
import { mainOutRoutes } from './mainOut';
import { PageEnum } from '/@/enums/pageEnum';
import { t } from '/@/hooks/web/useI18n';
//将同级目录下的modules文件路由进行加载
const modules = import.meta.glob('./modules/**/*.ts', { eager: true });
const routeModuleList: AppRouteModule[] = [];
// 加入到路由集合中
Object.keys(modules).forEach((key) => {
const mod = (modules as Recordable)[key].default || {};
const modList = Array.isArray(mod) ? [...mod] : [mod];
routeModuleList.push(...modList);
});
export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList];
export const RootRoute: AppRouteRecordRaw = {
path: '/',
name: 'Root',
redirect: PageEnum.BASE_HOME,
meta: {
title: 'Root',
},
};
export const LoginRoute: AppRouteRecordRaw = {
path: '/login',
name: 'Login',
//新版后台登录,如果想要使用旧版登录放开即可
// component: () => import('/@/views/sys/login/Login.vue'),
component: () => import('/@/views/system/loginmini/MiniLogin.vue'),
meta: {
title: t('routes.basic.login'),
},
};
//update-begin---author:wangshuai ---date:20220629 for:auth2登录页面路由------------
export const Oauth2LoginRoute: AppRouteRecordRaw = {
path: '/oauth2-app/login',
name: 'oauth2-app-login',
//新版钉钉免登录,如果想要使用旧版放开即可
// component: () => import('/@/views/sys/login/OAuth2Login.vue'),
component: () => import('/@/views/system/loginmini/OAuth2Login.vue'),
meta: {
title: t('routes.oauth2.login'),
},
};
//update-end---author:wangshuai ---date:20220629 for:auth2登录页面路由------------
/**
* 【通过token直接静默登录】流程办理登录页面 中转跳转
*/
export const TokenLoginRoute: AppRouteRecordRaw = {
path: '/tokenLogin',
name: 'TokenLoginRoute',
component: () => import('/@/views/sys/login/TokenLoginPage.vue'),
meta: {
title: '带token登录页面',
ignoreAuth: true,
},
};
// Basic routing without permission
export const basicRoutes = [LoginRoute, RootRoute, ...mainOutRoutes, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE, TokenLoginRoute, Oauth2LoginRoute];
PS:...是扩展运算符。对于数组和对象就是将运算符后面变量里的东西拆下来,放入数组中。
由上面的代码可知,根路由是‘/’,会重定向到'/dashboard/analysis'下,查找所有路由文件(src/router/routes文件下所有的.ts文件)
由路由可知,重定向后加载组件Layout(src/layouts/default/index.vue)
<template>
<Layout :class="prefixCls" v-bind="lockEvents">
<LayoutFeatures />
<LayoutHeader fixed v-if="getShowFullHeaderRef" />
<Layout :class="[layoutClass]">
<LayoutSideBar v-if="getShowSidebar || getIsMobile" /><!-- 左侧菜单栏 -->
<Layout :class="`${prefixCls}-main`">
<LayoutMultipleHeader /><!-- 主题内容(欢迎进入XXX,以及管理员啥的,那一行) -->
<LayoutContent /><!-- 主页内容 -->
<LayoutFooter />
</Layout>
</Layout>
</Layout>
</template>
LayoutSideBar组件:src/layouts/default/sider/index.vue
<template>
<Drawer
v-if="getIsMobile"
placement="left"
:class="prefixCls"
:width="getMenuWidth"
:getContainer="null"
:visible="!getCollapsed"
@close="handleClose"
>
<Sider />
</Drawer>
<MixSider v-else-if="getIsMixSidebar" />
<Sider v-else />
</template>
Drawer:是ant-design-vue的抽屉组件
Sider:src/layouts/default/sider/LayoutSider.vue,在LayoutSider.vue的LayoutMenu组件中加载了左侧菜单的内容(src/layouts/default/menu/index.vue)。对菜单进行渲染。
路由保护(setupRouterGuard):路由参数是由getUserPermissionByToken接口(前端getMenuList方法:src/api/sys/menu.ts)进行获取,该前端方法在buildRoutesAction方法(src/store/modules/permission.ts)中调用处理,buildRoutesAction方法在createPermissionGuard方法(src/router/guard/permissionGuard.ts)中被调用并添加到路由上。
const routes = await permissionStore.buildRoutesAction();
// alert("permissionGuard+buildRoutesAction")
// console.error(routes)
routes.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw);
});