| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- import { PAGES, TABS } from "../ctx";
- import type { BackOptions, PageInstance, PushOptions } from "../types";
- import { storage, last, isNull, isEmpty, get, isFunction, toArray, map, debounce } from "../utils";
- // 路由信息类型
- type RouteInfo = {
- path: string;
- };
- // 跳转前钩子类型
- type BeforeEach = (to: RouteInfo, next: () => void) => void;
- // 登录后回调类型
- type AfterLogin = () => void;
- // 路由事件集合
- type Events = {
- beforeEach?: BeforeEach;
- afterLogin?: AfterLogin;
- };
- // 路由核心类
- export class Router {
- private _events = {} as Events; // 事件存储
- // 获取缓存的路由参数
- params() {
- const data = storage.get("router-params") as UTSJSONObject;
- if (isNull(data)) {
- return {} as UTSJSONObject;
- }
- return data;
- }
- // 获取默认路径,支持 home 和 login
- defaultPath(name: "home" | "login") {
- const paths = {
- home: PAGES[0].path, // 首页为第一个页面
- login: "/pages/user/login"
- };
- return get(paths, name) as string;
- }
- // 获取当前页面栈的所有页面实例
- getPages(): PageInstance[] {
- return map(getCurrentPages(), (e) => {
- let path = e.route!;
- // 根路径自动转为首页
- if (path == "/") {
- path = this.defaultPath("home");
- }
- // 补全路径前缀
- if (!path.startsWith("/")) {
- path = "/" + path;
- }
- // 获取页面样式
- const style = PAGES.find((e) => e.path == path)?.style;
- // 获取页面暴露的方法
- // @ts-ignore
- let exposed = e.vm as any;
- // #ifdef H5
- exposed = get(e, "vm.$.exposed");
- // #endif
- // 获取页面 query 参数
- const query = (get(e, "options") ?? {}) as UTSJSONObject;
- return {
- path,
- // @ts-ignore
- vm: e.vm!,
- // @ts-ignore
- exposed,
- style,
- query,
- isCustomNavbar: style?.navigationStyle == "custom"
- } as PageInstance;
- });
- }
- // 获取指定路径的页面实例
- getPage(path: string) {
- return this.getPages().find((e) => e.path == path);
- }
- // 获取当前路由页面实例
- route() {
- return last(this.getPages());
- }
- // 获取当前页面路径
- path() {
- return this.route()?.path ?? "";
- }
- // 简单跳转页面(默认 navigateTo)
- to(path: string) {
- this.push({
- path
- });
- }
- // 路由跳转,支持多种模式和参数
- push(options: PushOptions) {
- let {
- query = {},
- params = {},
- mode = "navigateTo",
- path,
- success,
- fail,
- complete,
- animationType,
- animationDuration,
- events
- } = options;
- // 拼接 query 参数到 url
- if (!isEmpty(query)) {
- const arr = toArray(query, (v, k) => {
- return `${k}=${v}`;
- });
- path += "?" + arr.join("&");
- }
- // params 通过 storage 临时存储
- if (!isEmpty(params)) {
- storage.set("router-params", params, 0);
- }
- // tabBar 页面强制使用 switchTab 跳转
- if (this.isTabPage(path)) {
- mode = "switchTab";
- }
- // 跳转执行函数
- const next = () => {
- switch (mode) {
- case "navigateTo":
- uni.navigateTo({
- url: path,
- success,
- events,
- fail,
- complete,
- animationType,
- animationDuration
- });
- break;
- case "redirectTo":
- uni.redirectTo({
- url: path,
- success,
- fail,
- complete
- });
- break;
- case "reLaunch":
- uni.reLaunch({
- url: path,
- success,
- fail,
- complete
- });
- break;
- case "switchTab":
- uni.switchTab({
- url: path,
- success,
- fail,
- complete
- });
- break;
- }
- };
- // 跳转前钩子处理
- if (isFunction(this._events["beforeEach"])) {
- (this._events["beforeEach"] as BeforeEach)(
- {
- path
- },
- next
- );
- } else {
- next();
- }
- }
- // 回到首页
- home() {
- this.push({
- path: this.defaultPath("home")
- });
- }
- // 返回上一页,若为首页则回首页
- back(options: BackOptions | null = null) {
- if (this.isFirstPage()) {
- this.home();
- } else {
- uni.navigateBack({ ...(options ?? {}) });
- }
- }
- // 执行当前页面暴露的方法
- callMethod(name: string, data?: any): any | null {
- const fn = get(this.route()!, `$vm.$.exposed.${name}`) as (d?: any) => any | null;
- if (isFunction(fn)) {
- return fn(data);
- }
- return null;
- }
- // 判断页面栈是否只有一个页面
- isFirstPage() {
- return getCurrentPages().length == 1;
- }
- // 判断是否为首页
- isHomePage() {
- return this.path() == this.defaultPath("home");
- }
- // 判断是否为自定义导航栏页面
- isCustomNavbarPage() {
- return this.route()?.isCustomNavbar ?? false;
- }
- // 判断是否为当前页面
- isCurrentPage(path: string) {
- return this.path() == path;
- }
- // 判断是否为 tab 页面
- isTabPage(path: string | null = null) {
- if (path == null) {
- path = this.path();
- }
- if (path == "/") {
- path = this.defaultPath("home");
- }
- return !isNull(TABS.find((e) => path == e.pagePath));
- }
- // 判断是否为登录页
- isLoginPage(path: string) {
- return path == this.defaultPath("login");
- }
- // 跳转到登录页(防抖处理)
- login = debounce(() => {
- if (!this.isLoginPage(this.path())) {
- this.push({
- path: "/pages/user/login",
- mode: "reLaunch"
- });
- }
- }, 300);
- // 登录成功后跳转逻辑
- nextLogin() {
- const pages = this.getPages();
- // 找到登录页的索引
- const index = pages.findIndex((e) => this.defaultPath("login").includes(e.path));
- // 未找到,则跳回首页
- if (index < 0) {
- this.home();
- } else {
- this.back({
- delta: pages.length - index
- });
- }
- // 登录后回调
- if (isFunction(this._events["afterLogin"])) {
- (this._events["afterLogin"] as AfterLogin)();
- }
- // 触发全局 afterLogin 事件
- uni.$emit("afterLogin");
- }
- // 注册跳转前钩子
- beforeEach(callback: BeforeEach) {
- this._events["beforeEach"] = callback;
- }
- // 注册登录后回调
- afterLogin(callback: AfterLogin) {
- this._events["afterLogin"] = callback;
- }
- }
- // 单例导出
- export const router = new Router();
|