diff --git a/README.md b/README.md index 69990848d2c9f8a0834fa0a39ca2b117b550a232..4d02b45cfaf20d1b11a0c95afc2e74dfce2907c3 100644 --- a/README.md +++ b/README.md @@ -283,6 +283,7 @@ router.beforeEach((to, from, next) => { - `next()`: 执行默认路由跳转逻辑 - `next(false)`: 终止跳转逻辑 - `next({ path: '/' })`: 跳转到不同的页面 + - `next({ path: '/', navType: 'replaceAll' })`: 改变当前跳转类型并跳转到不同的页面,可以通过`navType`指定新的跳转类型。(实例为中断当前导航,改用`replaceAll`方法跳转到新的页面) #### 全局后置钩子 afterEach 你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身 diff --git a/src/index.ts b/src/index.ts index e45bd0a7095cd678a48c8e2be481c1e0d1143c98..f628ec972b07d297f8e35f75f747e5ba49ef1b88 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ /* * @Author: 徐庆凯 * @Date: 2023-03-13 15:48:09 - * @LastEditTime: 2023-04-27 13:10:08 + * @LastEditTime: 2023-05-08 13:33:29 * @LastEditors: weisheng * @Description: * @FilePath: \uni-mini-router\src\index.ts @@ -9,7 +9,7 @@ */ import { routeKey, routerKey } from './symbols' import { getCurrentPageRoute, navjump, registerEachHooks, rewriteNavMethod, saveCurrRouteByCurrPage } from './router' -import type { AfterEachGuard, BeforeEachGuard, Route, RouteLocationRaw, Router, RouterOptions } from './interfaces/index' +import type { AfterEachGuard, BeforeEachGuard, Route, RouteBackLocation, RouteLocationRaw, Router, RouterOptions } from './interfaces/index' import { shallowRef, unref } from 'vue' import { isEmptyObject } from './utils' /** @@ -35,8 +35,8 @@ export function createRouter(options: RouterOptions): Router { pushTab(to: RouteLocationRaw) { return navjump(to, this, 'pushTab') }, - back(level: number = 1) { - return uni.navigateBack({ delta: level }) + back(to?: RouteBackLocation) { + return uni.navigateBack(to) }, beforeEach(userGuard: BeforeEachGuard) { registerEachHooks(router, 'beforeHooks', userGuard) @@ -52,18 +52,16 @@ export function createRouter(options: RouterOptions): Router { app.mixin({ beforeCreate() { if (this.$mpType === 'page') { - saveCurrRouteByCurrPage(router) if (router.guardHooks.afterHooks && router.guardHooks.afterHooks[0]) { const from: Route = router.route.value const to: Route = getCurrentPageRoute(router) // 当前页面路由信息 router.guardHooks.afterHooks[0].call(null, to, from) } + saveCurrRouteByCurrPage(router) } }, onLoad(option: Record | undefined) { - const query: Record | undefined = router.route.value.query // query - const params: Record | undefined = router.route.value.params // params - if (!isEmptyObject(option) && isEmptyObject(query) && isEmptyObject(params)) { + if (!isEmptyObject(option) && isEmptyObject(router.route.value.query) && isEmptyObject(router.route.value.params)) { router.route.value = { ...router.route.value, query: option } } } diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index faab59a864fb8d65710facb62907f378e2f65981..51c74937329c3ee4ad7a1bd0dcca3fe80f21b13d 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -1,7 +1,7 @@ /* * @Author: 徐庆凯 * @Date: 2023-03-13 15:48:09 - * @LastEditTime: 2023-04-27 15:52:35 + * @LastEditTime: 2023-05-08 13:52:46 * @LastEditors: weisheng * @Description: * @FilePath: \uni-mini-router\src\interfaces\index.ts @@ -18,7 +18,7 @@ export interface Router { route: Ref // 当前路由信息 routes: any // 路由表 readonly guardHooks: GuardHooksConfig // 守卫钩子 - back(level?: number): void + back(to?: RouteBackLocation): void push(to: RouteLocationRaw): void replace(to: RouteLocationRaw): void replaceAll(to: RouteLocationRaw): void @@ -28,7 +28,7 @@ export interface Router { install(App: any): void } -export type BeforeEachGuard = (to: Route, from: Route, next: (rule?: Route | boolean) => void) => void // 全局前置守卫函数 +export type BeforeEachGuard = (to: Route, from: Route, next: (rule?: NextRouteLocationRaw | boolean) => void) => void // 全局前置守卫函数 export type AfterEachGuard = (to: Route, from: Route) => void // 全局后置守卫函数 export interface GuardHooksConfig { @@ -37,11 +37,11 @@ export interface GuardHooksConfig { } export interface RouteLocationBase { - animationType?: startAnimationType | endAnimationType // 动画类型 + animationType?: StartAnimationType | EndAnimationType // 动画类型 animationDuration?: number // 动画时间 } -export type startAnimationType = +export type StartAnimationType = | 'slide-in-right' | 'slide-in-left' | 'slide-in-top' @@ -51,7 +51,7 @@ export type startAnimationType = | 'zoom-out' | 'zoom-fade-out' | 'none' -export type endAnimationType = +export type EndAnimationType = | 'slide-out-right' | 'slide-out-left' | 'slide-out-top' @@ -64,17 +64,24 @@ export type endAnimationType = // name与params组合 export interface RouteNameLocation extends RouteLocationBase { - name: string - params?: Record + name: string // 路由名称 + params?: Record // 参数 } // path与query组合 export interface RoutePathLocation extends RouteLocationBase { - path: string - query?: Record + path: string // 路由路径 + query?: Record // 参数 } + +// back方法参数 +export interface RouteBackLocation extends RouteLocationBase { + animationType: EndAnimationType + delta?: number // 返回的页面数,如果 delta 大于现有页面数,则返回到首页。 +} + export type RouteUrlLocation = string -export type RouteLocationRaw = RouteUrlLocation | RouteNameLocation | RoutePathLocation +export type RouteLocationRaw = RouteUrlLocation | RouteNameLocation | RoutePathLocation // 路由位置 // 创建路由实例的选项 export interface RouterOptions { @@ -84,17 +91,51 @@ export interface RouterOptions { // 路由信息 export interface Route { fullPath?: string + aliasPath?: string name?: string path?: string query?: Record params?: Record } -// export interface RouteRule { -// path: string // pages.json中的path 必须加上 '/' 开头 -// name?: string // 命名路由 -// meta?: any // 其他格外参数 -// [propName: string]: any -// } +// 导航类型 export type NAVTYPE = 'push' | 'replace' | 'replaceAll' | 'pushTab' | 'back' +export type NavMethodType = 'navigateTo' | 'redirectTo' | 'reLaunch' | 'switchTab' | 'navigateBack' + +// 导航类型枚举 +export enum NavTypeEnum { + push = 'navigateTo', + replace = 'redirectTo', + replaceAll = 'reLaunch', + pushTab = 'switchTab', + back = 'navigateBack' +} + +// 导航类型枚举反向映射 +// export enum NavTypeReverseEnum { +// navigateTo = 'push', +// redirectTo = 'replace', +// reLaunch = 'replaceAll', +// switchTab = 'pushTab', +// navigateBack = 'back' +// } export type HookType = 'beforeHooks' | 'afterHooks' -export const NavMethod = ['navigateTo', 'redirectTo', 'reLaunch', 'switchTab', 'navigateBack'] +export const NavMethod: NavMethodType[] = ['navigateTo', 'redirectTo', 'reLaunch', 'switchTab', 'navigateBack'] + +// next方法 +// name与params组合 +export interface NextRouteNameLocation extends RouteNameLocation { + navType?: NAVTYPE // 导航类型 +} + +// path与query组合 +export interface NextRoutePathLocation extends RoutePathLocation { + navType?: NAVTYPE // 导航类型 +} + +// back方法参数 +export interface NextRouteBackLocation extends RouteBackLocation { + navType?: NAVTYPE // 导航类型 +} + +// Next方法入参 +export type NextRouteLocationRaw = RouteUrlLocation | NextRouteNameLocation | NextRoutePathLocation | NextRouteBackLocation diff --git a/src/router/index.ts b/src/router/index.ts index b0989947ec11b1fff62f5d084619af28db711039..75bc76410ed5eef181226c2e36560429302a37da 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -2,14 +2,26 @@ /* * @Author: 徐庆凯 * @Date: 2023-03-13 15:56:28 - * @LastEditTime: 2023-05-06 20:06:00 + * @LastEditTime: 2023-05-08 14:03:17 * @LastEditors: weisheng * @Description: * @FilePath: \uni-mini-router\src\router\index.ts * 记得注释 */ -import { AfterEachGuard, BeforeEachGuard, HookType, NavMethod, NAVTYPE, Route, RouteLocationRaw, Router } from '../interfaces' +import { + AfterEachGuard, + BeforeEachGuard, + HookType, + NavMethod, + NAVTYPE, + NavTypeEnum, + NextRouteBackLocation, + NextRouteLocationRaw, + Route, + RouteLocationRaw, + Router +} from '../interfaces' import { beautifyUrl, getUrlParams, queryStringify, setUrlParams } from '../utils' @@ -157,8 +169,8 @@ export function getCurrentPageRoute(router: Router): Route { */ export function getRouteByPath(path: string, router: Router): Route { path = path.split('?')[0] - const route: Route = router.routes.find((route: { path: string }) => { - return route.path === path + const route: Route = router.routes.find((route: Route) => { + return route.path === path || route.aliasPath === path }) return route } @@ -193,16 +205,20 @@ export function rewriteNavMethod(router: Router) { if (router.guardHooks.beforeHooks && router.guardHooks.beforeHooks[0]) { const to: Route = getRouteByPath(options.url, router) guardToPromiseFn(router.guardHooks.beforeHooks[0], to, router.route.value) - .then((resp: any) => { - if (resp && resp.to) { - const path = getRoutePath(resp.to, router) - if (path && path !== options.url.split('?')[0]) { - oldMethods[name]({ url: path }) + .then((resp) => { + if (resp === true) { + oldMethods[name](options) + } else { + if (typeof resp === 'string') { + const url: string = getRoutePath(resp, router) + oldMethods[name]({ url: url }) + } else if ((resp as NextRouteBackLocation).navType === 'back') { + oldMethods['navigateBack'](resp) } else { - oldMethods[name](options) + const url: string = getRoutePath(resp as RouteLocationRaw, router) + name = resp.navType ? NavTypeEnum[resp.navType] : name + oldMethods[name]({ url: url }) } - } else { - oldMethods[name](options) } }) .catch((error) => { @@ -224,15 +240,15 @@ export function rewriteNavMethod(router: Router) { * @returns */ export function guardToPromiseFn(guard: BeforeEachGuard, to: Route, from: Route) { - return new Promise((reslove, reject) => { - const next: ((rule?: Route | boolean) => void) | any = (rule?: Route | boolean) => { + return new Promise((reslove, reject) => { + const next: ((rule?: NextRouteLocationRaw | boolean) => void) | any = (rule?: NextRouteLocationRaw | boolean) => { next._called = true if (rule === false) { reject({}) - } else if (rule === undefined) { - reslove({ to: to }) + } else if (rule === undefined || rule === true) { + reslove(true) } else { - reslove({ to: rule }) + reslove(rule) } } const guardReturn = guard.call(undefined, to, from, next)