痛点 & 目标
在微信小程序中进行页面跳转时高度依赖文件路径,但当我们的目录层级过深,或者参数过多时,就会难以维护:
wx.navigateTo(`/pages/mine/address/address?id=${this.data.id}&pageType=EDIT&jumpBack=Y`);
仔细分析,就会发现有以下几个痛点:
- 路由路径和目录结构绑定,任何对目录结构的修改都需要对项目中全部路由路径进行修改
 - 参数可读性差,难以维护
 
而我们的目标是:
- 解藕路由系统和目录结构,尽可能降低目录结构修改对路由产生的影响
 - 优化参数的传递方式,尽可能摆脱难以维护的字符串形式
 - 参数有迹可循,在不使用 Typescript 等工具时,尽可能让数据流清晰
 
路由系统实现
从 Vue Router 中汲取灵感,我们可以把所有的页面映射为一个对象,对象的 Key 类似 Vue Router 中的 name,路由跳转时只使用 key 值即可。当目录结构发生改变时只需要修改键值对中的 Value 即可,页面中的代码逻辑无需任何改动。新建 config/routes.js。
export const Routes = {
  Index: '/pages/index/index',
  Mine: '/pages/mine/mine',
  About: '/pages/static/about/about',
  Register: '/pages/register/register',
	Address: '/pages/mine/address/address'
	...
};
新建 utils/route.js。
import { Routes } from '../config/routes';
/**
 * 构建 url 参数
 * @param {string|object|null} params
 */
export const buildParams = (params) => {
  let fullParamStr;
  if (!params) {
    fullParamStr = '';
  } else if (typeof params === 'string') {
    fullParamStr = params;
  } else {
    fullParamStr = Object.keys(params)
      .map((key, index) => {
        const prefix = index === 0 ? `?` : `&`;
        return `${prefix}${key}=${params[key]}`;
      })
      .join('');
  }
  return fullParamStr;
};
/**
 * 高阶函数构建路由跳转模块
 * @param {Function} method
 */
const generateRoute = (method) => (routeName, params, events) => {
  const routePath = Routes[routeName];
  if (!routePath) {
    console.error(`The RouteName must be one of: ${Object.keys(Routes).join(', ')}`);
    return;
  }
  return new Promise((resolve, reject) => {
    const options = {
      url: routePath + buildParams(params),
      success: resolve,
      fail: reject,
    };
    if (events) options.events = events;
    method(options);
  });
};
export const switchTab = generateRoute(wx.switchTab);
export const reLaunch = generateRoute(wx.reLaunch);
export const navigateTo = generateRoute(wx.navigateTo);
export const redirectTo = generateRoute(wx.redirectTo);
export default { switchTab, reLaunch, navigateTo, redirectTo };
使用示例:
import { navigateTo, reLaunch } from '../utils/route';
// 简单跳转
navigateTo('Register');
// 传入字符型作为参数
reLaunch('Index', `?withMessage=${this.data.message}`);
// 传入对象作为参数。同时支持 eventChannel 配置
navigateTo(
  'Address',
  { id: this.data.id, pageType: 'EDIT', jumpBack: 'Y' },
  // 需要在 Address 中触发 eventChannel.emit('edited')
  { edited: this.refreshAddress.bind(this) },
);
如何接收参数
为了让路由系统中的数据流向保持清晰,因此我们应当约定:每个页面的参数都使用解构语法。
// ok
onLoad(options) {
}
// better
onLoad({ id, pageType = 'CREATE', jumpBack = 'Y' }) {
}