导航

    Taro 社区

    Taro

    • 注册
    • 登录
    • 搜索
    • 版块
    • 最新
    • 话题
    • 热门
    • 群组
    1. 主页
    2. lblblong
    L
    • 资料
    • 关注
    • 粉丝
    • 主题
    • 帖子
    • 最佳
    • 群组

    lblblong

    @lblblong

    0
    声望
    2
    帖子
    2190
    资料浏览
    0
    粉丝
    0
    关注
    注册时间 最后登录

    lblblong 关注

    lblblong 发布的帖子

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

      小程序的路由有什么问题

      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 导出 params 和 data 的类型定义,这样生成的 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示例

      详细的文档:查看文档

      发布在 Taro 实践 + 案例
      L
      lblblong
    • Taro 路由增强,任意传参、跳转页面取值、路由中间件

      前言

      最近用Taro开发小程序发现一些不好用的地方:

      • 页面传参需要手动拼接 url
      • 页面传参无法携带大量任意类型数据
      • 跳页面取值比较麻烦(比如填写表单跳页面选择城市,往往需要全局存储,回到页面再去取,也可以通过event,但是总要写很多代码)

      为了实现上面的需求更方便,于是封装了一下:tarojs-router

      看看 tarojs-router 如何解决上面的问题

      一、页面传参

      // ✘ 手动拼接路径,无法传任意类型,数据量有限制
      Taro.navigateTo({
        url: '/pages/user/index?name=李四&id=1',
      })
      
      // ✔ tarojs-router 自动拼接,可传任意类型任意大小的数据
      Router.navigate(
        { url: '/pages/user/index' },
        {
          // url 参数,自动拼接
          params: { id: 1, name: '李四' },
          // 可携带其他数据,任意类型
          data: [1, 2, 3, 4],
        }
      )
      
      // 目标页面获取数据,函数组件:
      const { params, data } = useRouter()
      // 目标页面获取数据,Class 组件:
      const data = Router.getData()
      const params = getCurrentInstance().router?.params
      

      二、跳页面取值

      实现这种需求,简单做法是跳转过去后把选中的值全局存储起来,回到页面后再去取,自己实现这个过程比较麻烦

      熟悉flutter的可能知道

      // 跳转到目标页面
      final cityData = await Navigator.push(...)
      
      // 返回值到上一个页面
      Navigator.pop({cityName: '深圳', adcode: 'xxxx'})
      

      tarojs-router 中写法基本一致,内部通过 promise 实现

      // ✔ tarojs-router 封装了这个过程,直接使用
      const cityData = await Router.navigate({ url: '/pages/sel-city/index' })
      console.log(cityData?.cityName)
      
      // src/pages/sel-city/index.tsx
      const { backData } = useRouter()
      backData({ cityName: '深圳', adcode: 'xxxx' })
      

      三、路由中间件(附加功能)

      tarojs-router 提供和 koa 一致的路由中间件功能

      // 实现一个登录检查的路由中间件
      // auth-check.ts
      export const AuthCheck: IMiddlware<{ 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) toLogin()
            throw Error('该页面必须要登陆:' + ctx.route.url)
          }
        }
        await next()
      }
      
      // router.ts
      Router.config({
        middlewares: [AuthCheck],
      })
      
      // ext 携带 mustLogin 并且为 true 则会检查 token,token 不存在则跳转登录
      Router.navigate({ url: '/pages/home/index', ext: { mustLogin: true } })
      

      文档

      tarojs-router 文档

      示例

      Demo(代码)
      Demo(微信开发者工具打开)

      发布在 Taro 实践 + 案例
      L
      lblblong