Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[自荐] 可能是最好用的 Taro 小程序路由库 #1741

Open
lblblong opened this issue Apr 28, 2021 · 0 comments
Open

[自荐] 可能是最好用的 Taro 小程序路由库 #1741

lblblong opened this issue Apr 28, 2021 · 0 comments

Comments

@lblblong
Copy link

tarojs-router-next

小程序的路由有什么问题

  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示例

详细的文档:查看文档

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants