基于Taro封装简单的路由管理

1,436 阅读3分钟

初衷

在使用Taro或者是uniapp,开发的时候,跳转都需要写全路径,感觉非常的麻烦。

  • 场景:想象一下,如果我们需要在跳转的时候需要判断要跳过去的页面是需要登录的。 如果我们不把路由跳转做第二次封装,可以想象的是,代码是非常混乱,且不好管理和维护

思路

  1. 使用一个对象装入整个项目的路由
  2. 把Taro路由跳转函数做二次封装
  3. 拿个中间件做路由的options参数,判断和路由路径拼装
  4. 在跳转前,在写个函数来判断当前的状态是否是运行跳转到对应的页面(比如:有些页面是需要登录才能跳转的)
  5. 在所有条件都满足的情况下,进行跳转页面

代码实现

import { queryParams } from '../utils/utils'
import Taro from '@tarojs/taro'
import { RouterObj, RouterSkip } from '../type/router'

const router: RouterObj = Object.freeze({
    'index': '/pages/index/index', //首页
    'my': '/pages/my/index',//我的
})

const router_jurisdiction: string[] = ['my'] //那些页面需要登录权限

// 暴露路由接口
export class Router {
    /**
     * 取出路由地址
     * @param key 路由对应的key
     * @returns string
     */
    static getRouter(key: string): string {
        return router[key];
    }
    /**
     * 拼接路由和参数
     * @param url 路由对应的key
     * @param data 页面之间要传的参数
     * @returns 
     */
    static urlRoute<T>(url: string, data?: T): string {
        // 获取要跳转的地址
        url = router[url];
        if (!url) return "";
        let str = queryParams((data as any)); //把对象转换成路由后面的参数
        return url + str; //返回路由和参数
    }

    // 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
    static switchTab(options: RouterSkip): void {
        jointRouter(options, 'switchTab')
    }

    // 关闭所有页面,打开到应用内的某个页面
    static reLaunch(options: RouterSkip): void {
        jointRouter(options, 'reLaunch')
    }

    // 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
    static redirectTo(options: RouterSkip): void {
        jointRouter(options, 'redirectTo')

    }

    // 保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 Taro.navigateBack 可以返回到原页面。小程序中页面栈最多十层。
    static navigateTo(options: RouterSkip): void {
        jointRouter(options, 'navigateTo')
    }

    // 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。
    static navigateBack(options: RouterSkip): void {
        jointRouter(options, 'navigateBack')
    }
}

// 中间件,路由跳转前代理
function jointRouter(options: RouterSkip, type: string): boolean {
    if (!options?.url) return false //判断当前是否传入路由地址
    let key = options.url;//保存当前路由key
    let url = Router.urlRoute<RouterObj>(options?.url, options?.data ?? {}); //从注册中获取路由
    if (!url) return false //判断是否从注册中获取路由
    options.url = url;
    new TaroRouter(options, type, key) // 执行跳转处理
    return true
}

// 路由跳转处理
class TaroRouter {
    protected options: RouterSkip //对应的参数
    protected type: string // 要跳转的类型
    protected key: string // 路由的key 用于判断要跳转的路由是否需要登录

    public constructor(options: RouterSkip, type: string, key: string) {
        this.options = options;
        this.type = type;
        this.key = key;
        this.intercept()
    }

    // 路由拦截
    private intercept() {
        // 判断是否登录过
        let { key } = this;
        if (router_jurisdiction.includes(key)) {
            Taro.getBackgroundFetchToken({
                success: (res) => {
                    console.log(res)
                    this.taroRouter()
                },
                fail: (err) => {
                    console.log(err);
                    // 如果要跳转的页面是需要登录的,但是当前状态是没有登录的
                    // TODO:: 当前没有登录需要做的处理
                }
            })
        } else {
            this.taroRouter()
        }
    }

    // 路由跳转
    private taroRouter() {
        let { options, type } = this;
        if (!Taro.hasOwnProperty(type)) return false;
        Taro[type](options);
    }
}

// 类型文件
import { Record } from '@tarojs/cli'

export interface RouterSkip {
    url: string //需要跳转的应用内非 tabBar 的页面的路径, 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如 'path?key=value&key2=value2'
    data?: RouterObj //要传入下个页面的参数
    complete?: Function//接口调用结束的回调函数(调用成功、失败都会执行)
    fail?: Function //接口调用失败的回调函数
    success?: Function //接口调用成功的回调函数
    events?: Record//页面间通信接口,用于监听被打开页面发送到当前页面的数据
}