diff --git a/.vscode/settings.json b/.vscode/settings.json index 378cd3b2..ecb5e3f5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -84,13 +84,13 @@ "editor.defaultFormatter": "esbenp.prettier-vscode" }, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, - "source.fixAll.stylelint": true + "source.fixAll.eslint": "explicit", + "source.fixAll.stylelint": "explicit" }, "[vue]": { "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, - "source.fixAll.stylelint": true + "source.fixAll.eslint": "explicit", + "source.fixAll.stylelint": "explicit" } }, "i18n-ally.localesPaths": ["src/locales/lang"], diff --git a/src/main.ts b/src/main.ts index 1c4c808b..c88ec766 100644 --- a/src/main.ts +++ b/src/main.ts @@ -44,7 +44,7 @@ async function bootstrap() { setupRouter(app); // router-guard - // 路由守卫 + // 路由守卫(全局守卫) setupRouterGuard(router); // Register global directive diff --git a/src/router/guard/index.ts b/src/router/guard/index.ts index c5677499..83aca759 100644 --- a/src/router/guard/index.ts +++ b/src/router/guard/index.ts @@ -15,9 +15,14 @@ import { createParamMenuGuard } from './paramMenuGuard'; // Don't change the order of creation export function setupRouterGuard(router: Router) { + // 改变页面的加载状态: 修改to.meta.loaded, 添加loadedPageMap createPageGuard(router); + // 页面 loading 状态: openPageLoading createPageLoadingGuard(router); + + // 切换路由时,中断正在进行的http请求 createHttpGuard(router); + // createScrollGuard(router); createMessageGuard(router); createProgressGuard(router); @@ -48,17 +53,21 @@ function createPageGuard(router: Router) { // Used to handle page loading status function createPageLoadingGuard(router: Router) { + // 在全局路由守卫中使用 pinia store const userStore = useUserStoreWithOut(); const appStore = useAppStoreWithOut(); const { getOpenPageLoading } = useTransitionSetting(); + router.beforeEach(async (to) => { + // 没有token ,直接跳过守卫 if (!userStore.getToken) { return true; } + // 页面加载过,也直接跳过守卫( 这样就只针对初次加载的页面有效) if (to.meta.loaded) { return true; } - + // 对 computed 进行 unref() if (unref(getOpenPageLoading)) { appStore.setPageLoadingAction(true); return true; @@ -84,8 +93,11 @@ function createPageLoadingGuard(router: Router) { */ function createHttpGuard(router: Router) { const { removeAllHttpPending } = projectSetting; + let axiosCanceler: Nullable; + // 如果配置了 取消 http 请求 ,就实例化 AxiosCanceler if (removeAllHttpPending) { + // 虽然是不同的 AxiosCanceler 实例,但是 removeAllPending() 访问的全局的属性 axiosCanceler = new AxiosCanceler(); } router.beforeEach(async () => { diff --git a/src/router/routes/index.ts b/src/router/routes/index.ts index 79115b79..ccb2b6e3 100644 --- a/src/router/routes/index.ts +++ b/src/router/routes/index.ts @@ -17,6 +17,7 @@ Object.keys(modules).forEach((key) => { routeModuleList.push(...modList); }); +// 在路由守卫中添加的动态路由 export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList]; // 根路由 @@ -43,7 +44,7 @@ export const LoginRoute: AppRouteRecordRaw = { export const basicRoutes = [ LoginRoute, RootRoute, - ...mainOutRoutes, + ...mainOutRoutes, // 框架以外的页面 REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE, ]; diff --git a/src/utils/http/axios/Axios.ts b/src/utils/http/axios/Axios.ts index e75dfdd2..723a21ea 100644 --- a/src/utils/http/axios/Axios.ts +++ b/src/utils/http/axios/Axios.ts @@ -88,10 +88,11 @@ export class VAxios { // Request interceptor configuration processing this.axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => { - // If cancel repeat request is turned on, then cancel repeat request is prohibited - const requestOptions = (config as unknown as any).requestOptions ?? this.options.requestOptions; + // If cancel repeat request is turned on, then cancel repeat request is prohibited + const requestOptions = + (config as unknown as any).requestOptions ?? this.options.requestOptions; const ignoreCancelToken = requestOptions?.ignoreCancelToken ?? true; - + // NOTE: 在 http 请求拦截器中,把 axios 的config直接添加到 axiosCanceler 中 !ignoreCancelToken && axiosCanceler.addPending(config); if (requestInterceptors && isFunction(requestInterceptors)) { @@ -202,7 +203,7 @@ export class VAxios { if (config.cancelToken) { conf.cancelToken = config.cancelToken; } - + if (config.signal) { conf.signal = config.signal; } diff --git a/src/utils/http/axios/axiosCancel.ts b/src/utils/http/axios/axiosCancel.ts index f115ccf5..4fc24e5c 100644 --- a/src/utils/http/axios/axiosCancel.ts +++ b/src/utils/http/axios/axiosCancel.ts @@ -1,6 +1,6 @@ import type { AxiosRequestConfig } from 'axios'; -// 用于存储每个请求的标识和取消函数 +// 用于存储每个请求的标识和取消函数(global settings) const pendingMap = new Map(); const getPendingUrl = (config: AxiosRequestConfig): string => { @@ -13,12 +13,17 @@ export class AxiosCanceler { * @param config 请求配置 */ public addPending(config: AxiosRequestConfig): void { + // 每次添加config 都先清除 this.removePending(config); + // 获取axios 配置中的请求 url 和请求方法,并作为key 添加到pendingMap 中 const url = getPendingUrl(config); + // abortController js API, 用于取消请求 const controller = new AbortController(); + // 向 axios 中注入新的属性 single, 其实就是abortController 的 single 属性 config.signal = config.signal || controller.signal; + // 存储每个请求的标识 if (!pendingMap.has(url)) { - // 如果当前请求不在等待中,将其添加到等待中 + // 如果当前请求不在等待中,将其添加到等待中, 每个请求 api ,就配置一个 AbortController 实例 pendingMap.set(url, controller); } } @@ -45,7 +50,7 @@ export class AxiosCanceler { // 如果当前请求在等待中,取消它并将其从等待中移除 const abortController = pendingMap.get(url); if (abortController) { - abortController.abort(url); + abortController.abort(url); // NOTE: 可以不用传参 } pendingMap.delete(url); } diff --git a/vite.config.ts b/vite.config.ts index 0c914370..010a7e45 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,5 +1,7 @@ import { defineApplicationConfig } from '@vben/vite-config'; +// TIPS: vite.config.ts 配置作为插件进行封装 + export default defineApplicationConfig({ overrides: { optimizeDeps: { @@ -32,5 +34,6 @@ export default defineApplicationConfig({ }, }, }, + base: '/vben', }, });