[开源] 一个 Taro 路由库:小程序的路由系统太难用了吧.. - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
lblblong
V2EX    分享创造

[开源] 一个 Taro 路由库:小程序的路由系统太难用了吧..

  •  
  •   lblblong 2021-04-22 14:39:26 +08:00 2840 次点击
    这是一个创建于 1680 天前的主题,其中的信息可能已经有所发展或是发生改变。

    小程序的路由有什么问题

    1. 路由跳转的页面 url 没有类型提示容易输错
    2. 路由传参需要手动拼接参数、无法携带任意类型、任意大小的数据
    3. 路由方法是异步的,页面通过 EventCannal 通信,事件的回调方法可读性差、耦合度高、只能在回调内部处理异常
    4. 路由跳转的鉴权等实现起来比较麻烦

    如何解决这些问题

    允许我先向你介绍: tarojs-router-next,这是一个 Taro 的路由辅助库,他提供以下特性帮助你方便的解决上面的问题

    • 自动生成带参数类型提示的路由方法
    • 允许传递任意类型、任意大小的参数数据
    • 同步的路由方法调用
    • koa 体验一致的路由中间件
    • 详细的文档

    1. 路由跳转的页面 url 没有类型提示容易输错

    tarojs-router-next 不需要使用者手写页面 url,它会监听项目 src/pages 内容变化,自动为使用者生成对应的路由方法并附加到 Router 类上,比如以下列子:

    左边的页面结构会生成右边的 Router.to** 系列方法,全都挂在 Router 类上

    2. 路由传参需要手动拼接参数、无法携带任意类型、任意大小的数据

    tarojs-router-next 允许直接传递一个对象给 params,它会把 params 展开拼接到 url 后面。并且还可以接收一个 data 参数,data 可以传递任意类型、任意大小的数据。

    Router.toDetail({ params: { id: 1 } }) Router.toDetail({ params: { id: 1, name: 'lbl' } }) Router.toDetail({ data: { name: 'taro', role: [1, 2, 3] } }) Router.toDetail({ data: 123 }) Router.toDetail({ data: true }) 

    并且可以通过页面下的 route.config.ts 导出 paramsdata 的类型定义,这样生成的 Router.to** 相关方法会带有类型提示

    // 导出 params 的类型,名字必须是 Params export type Params = { id: number name: string } // 导出 data 的类型,名字必须是 Data export type Data = { name: string role: number[] } 

    3. 路由方法是异步的,页面通过 EventCannal 通信,事件的回调方法可读性差、耦合度高、只能在回调内部处理异常

    tarojs-router-next 的路由跳转会返回一个 Promise,通过 async/await 可以写出同步的写法,详细参考 同步的路由方法

    // page/edit/index try { // 跳转页面选择城市 const cityData = await Router.toSelectCity() if( !cityData ) return // 赋值给表单项 this.form.city = cityData } catch ( err ) { console.log( err.message ) } // page/select-city/index Router.back() // 返回上一个页面,此时上一个页面拿到的是 null Router.back( { id: 1, name: '深圳' } ) // 返回上一个页面并返回城市数据 Router.back( new Error('用户取消选择') ) // 返回上一个页面并抛出异常 

    4. 路由跳转的鉴权等实现起来比较麻烦

    自己实现路由的鉴权是比较麻烦的事情,而 tarojs-router-next 提供与 koa 使用一致的路由中间件功能,详细参考 路由中间件

    注册一个路由中间件:

    import Taro from '@tarojs/taro' import { Middleware, registerMiddleware } from 'tarojs-router-next' export const M1: Middleware = async (ctx, next) => { console.log('中间件执行:', ctx.route.url) await next() console.log('中间件执行结束') } registerMiddleware(M1) 

    注册多个路由中间件:

    registerMiddlewares([M1, M2]) 

    有的时候我们希望某个中间件只为特定的页面工作,这个需求可以在中间件中增加判断条件来实现,但在中间件中做这些判断会使中间件的职能不够专一,并且这些判断逻辑无法在多个中间件中复用

    怎么解决呢,我们可以在注册中间件时传递一个方法,将本来要写到中间件中的判断逻辑抽取到该方法中。在路由进入时该方法会被调用并传入当前路由的上下文,若方法返回 true 则为当前路由执行这些中间件

    // 仅为 me 和 home 页面注册该路由中间件 registerMiddleware(Logger, (ctx) => { return ['/pages/me/index', '/pages/home/index'].indexOf(ctx.route.url) !== -1 }) // 注册多个中间件 registerMiddlewares([Logger, Auth], (ctx) => { return ['/pages/me/index', '/pages/home/index'].indexOf(ctx.route.url) !== -1 }) 

    一个检查用户是否登录的中间件示例:

    import Taro from '@tarojs/taro' import { Middleware, Router } from 'tarojs-router-next' export const AuthCheck: Middleware<{ mustLogin: boolean }> = async (ctx, next) => { if (ctx.route.ext?.mustLogin) { const token = Taro.getStorageSync('token') if (!token) { const { confirm } = await Taro.showModal({ title: '提示', content: '请先登录', }) if (confirm) Router.toLogin() // 打断路由执行 throw Error('该页面必须要登陆:' + ctx.route.url) } } await next() } 

    最后

    完整的代码示例:React 示例Vue3 示例

    详细的文档:查看文档

    7 条回复    2021-04-23 10:15:09 +08:00
    JenJieJu
        1
    JenJieJu  
       2021-04-22 15:37:35 +08:00
    不错不错,有几个问题:
    1. 可以管理路由栈吗
    2. 可以无限层次进入页面吗
    lblblong
        2
    lblblong  
    OP
       2021-04-22 16:05:23 +08:00
    @JenJieJu 我看了一些突破页面栈限制的方案,都有一个最大的问题就是:小程序的页面过渡动画无法自定义,所以体验上会出现用户返回上一个页面,页面却是从右边进来的..,所以我还是建议尽量从业务和交互的设计上避免超出限制

    管理路由是需要哪些支持呢
    weimo383
        3
    weimo383  
       2021-04-22 19:32:40 +08:00 via Android
    讲道理小程序为什么需要路由呢?状态管理存一下状态就行了呗。。。
    lblblong
        4
    lblblong  
    OP
       2021-04-23 09:30:09 +08:00
    @weimo383 这...是 GUI 程序都会要路由系统的吧
    weimo383
        5
    weimo383  
       2021-04-23 10:06:13 +08:00 via Android
    @lblblong 我还是不理解,浏览器地址栏在小程序中又没有。。。
    lblblong
        6
    lblblong  
    OP
       2021-04-23 10:14:26 +08:00
    @weimo383 小程序的每个页面都有地址的,比如你在小程序里分享了一篇文章给好友,分享出去的内容其实是:小程序 appid + 文章页面路径 /pages/article/index?id=123
    lblblong
        7
    lblblong  
    OP
       2021-04-23 10:15:09 +08:00
    @weimo383 好友点击你的分享的时候,就会直接进入文章详情页
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1163 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 17:45 PVG 01:45 LAX 09:45 JFK 12:45
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86