基于Taro的小程序路由封装

880 阅读1分钟
import Taro from '@tarojs/taro'

import { showToast } from '@utils/util.common'

/**
 * @description: 获取当前页面路由路径
 * @return {string} pages/index/index
 */
export function getCurrentRoute (): string {
  const pages = Taro.getCurrentPages()
  return pages?.[pages.length - 1]?.route ?? ''
}

/**
 * 返回手柄
 * @param {Number} delta 返回层数 默认值:1 返回首页:-1
 * @returns {Promise<null|any>}
 */
export async function backHandler (delta: number = 1): Promise<boolean> {
  const length: number = Taro.getCurrentPages()?.length

  // 首页无法返回
  if (length === 1) {
    console.error('禁止在首页调用此方法')
    return Promise.resolve(false)
  }

  return new Promise(resolve => {
    Taro.navigateBack({
      fail: () => resolve(false),
      success: () => resolve(true),
      delta: delta === -1 ? length : delta
    })
  })
}

/**
 * @description: 返回到指定页面
 * @param {string} path 需要返回页面的路径 例如: 'pages/index/index'
 * @return {*}
 */
export async function backToHandler (path: string): Promise<boolean> {
  const pages = Taro.getCurrentPages() ?? {}
  const len: number = pages.length ?? 0

  let delta: number = 0

  for (let i: number = 1; i <= len; i++) {
    if (pages?.[len - i]?.route !== path) {
      delta++
    } else {
      break
    }
  }

  return backHandler(delta)
}

/**
 * @description: 基础路由跳转方法
 * @param {string} method 跳转的方法
 * @return {Function} 该路由跳转方法的函数
 */
const baseRouterHandle = (method: string): Function => (path: string, params: object, force: boolean = false): Promise<boolean> => {
  const route = getCurrentRoute()

  if (!force && path.includes(route)) {
    return Promise.resolve(false)
  }

  let paramsJsonStr: string

  try {
    paramsJsonStr = JSON.stringify(params)
  } catch (error) {
    showToast(error)
    return Promise.resolve(false)
  }

  return new Promise(resolve => {
    Taro[method]({
      url: `/${path}?data=${paramsJsonStr}`,
      fail: () => resolve(false),
      success: () => resolve(true)
    })
  })
}

/**
 * @description: navigateTo 路由跳转方法
 * @param {string} path 要跳往的路由页面url pages/index/index
 * @param {object} param 要携带的参数 注: 会把参数变成字符串
 * @param {boolean} force 是否强制
 * @return {Promise} true 跳转成功 false 跳转失败
 */
export const navigateHandler = baseRouterHandle('navigateTo')

/**
 * @description: redirectTo 路由跳转方法
 * @param {string} path 要跳往的路由页面url
 * @param {object} param 要携带的参数 注: 会把参数变成字符串
 * @param {boolean} force 是否强制
 * @return {Promise} true 跳转成功 false 跳转失败
 */
export const redirectHandler = baseRouterHandle('redirectTo')

/**
 * @description: 解析路由传过来的参数
 * @param {object} params
 * @return {object} 解析后的对象
 */
export const getRouteParams = (params) => {
  let routeParams = {}
  try {
    const data = JSON.parse(params.data as string)
    routeParams = Object.freeze(data)
  } catch (error) {
    console.error(error)
  }
  return routeParams
}

配合FC组件使用的hook函数

import { useRef } from 'react'
import { useRouter } from '@tarojs/taro'

const defaultRouteParams = Object.freeze({ data: {}, parse: false })

interface UseVnRouterRes {
  [keyProp: string]: any
}

/**
 * @description: 获取路由参数
 * @param {string} key
 * @return {*}
 */
export default function useVnRouter (): UseVnRouterRes {
  const { params } = useRouter()

  const routeParams = useRef(defaultRouteParams)

  if (!routeParams.current.parse) {
    try {
      const data = JSON.parse(params.data as string)
      routeParams.current = Object.freeze({ data, parse: true })
    } catch (error) {
      routeParams.current = defaultRouteParams
    }
  }

  return routeParams.current.data
}