编写Taro本地插件生成路由函数

1,381 阅读3分钟

编写这个插件的初衷是因为不想跳转到一个页面,每次都要写一遍路由链接,类似于Taro.navigateTo({url:"xxx"}),而且如果要传入参数的话,还需要一个个拼接,很麻烦。那有没有一次性生成所有路由的函数的方法呢?并且不需要拼接参数呢? 答案就是Taro的插件功能。

一、编写本地插件

1、创建

首先进入Taro官方文档的进阶指南->插件功能,里面介绍了插件的使用。 因为我们不需要发布npm包,所以使用本地插件。

const config = {
  plugins: [
    // 引入 npm 安装的插件
    '@tarojs/plugin-mock', 
    // 引入 npm 安装的插件,并传入插件参数
    ['@tarojs/plugin-mock', {
      mocks: {
        '/api/user/1': {
          name: 'judy',
          desc: 'Mental guy'
        }
      }
    }],
    // 从本地绝对路径引入插件,同样如果需要传入参数也是如上
    '/absulute/path/plugin/filename',
  ]
}

在项目根目录中创建plugin -> xxx.js 然后在config->index.js中引入

2、编写

不知道是不是我的打开方式不对还是其他原因,官方文档中的例子一启动项目就报错。 后来修改了导出模块方式,才解决问题。

2.1主体

export default (ctx, options) => {
  // plugin 主体
  ctx.onBuildStart(() => {
    console.log('编译开始!')
  })
  ctx.onBuildFinish(() => {
    console.log('编译结束!')
  })
}

改为

module.exports = (ctx, options) => {
  // plugin 主体
  ctx.onBuildStart(() => {
    console.log('编译开始!')
  })
  ctx.onBuildFinish(() => {
    console.log('编译结束!')
  })
}

2.2生成模板

先想好你要生成的路由函数模板 因为项目使用了ts,所以我的模板如下

import Taro, { EventChannel, General } from "@tarojs/taro";

export enum NavigateType {
  /** 保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 Router.back 可以返回到原页面。小程序中页面栈最多十层。 */
  navigateTo = "navigateTo",
  /** 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。 */
  redirectTo = "redirectTo",
  /** 关闭所有页面,打开到应用内的某个页面 */
  reLaunch = "reLaunch",
  /** 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面 */
  switchTab = "switchTab",
}

interface ToRouterType<P> {
  params?: P;
  type?: NavigateType /** 接口调用结束的回调函数(调用成功、失败都会执行) */;
  complete?: (res: General.CallbackResult) => void;
  /** 页面间通信接口,用于监听被打开页面发送到当前页面的数据。 */
  events?: General.IAnyObject;
  /** 接口调用失败的回调函数 */
  fail?: (res: General.CallbackResult) => void;
  /** 接口调用成功的回调函数 */
  success?: (
    res: General.CallbackResult & { eventChannel: EventChannel }
  ) => void;
}

const navigateType = <P>(url: string, option?: ToRouterType<P>) => {
  const { type, params, success, fail, complete, events } = option ?? {
    type: NavigateType.navigateTo,
    params: {},
    success: () => {},
    fail: () => {},
    complete: () => {},
    events: undefined,
  };
  url = url + ganerateParams(params ?? {});
  switch (type) {
    case NavigateType.navigateTo:
      Taro.navigateTo({ url, success, fail, complete, events });
      break;
    case NavigateType.redirectTo:
      Taro.redirectTo({ url, success, fail, complete });
      break;
    case NavigateType.reLaunch:
      Taro.reLaunch({ url, success, fail, complete });
      break;
    case NavigateType.switchTab:
      Taro.switchTab({ url, success, fail, complete });
      break;
    default:
      Taro.navigateTo({ url, success, fail, complete, events });
  }
};

const ganerateParams = (params: { [key: string]: any }) => {
  return (
    "?" +
    Object.entries(params).reduce((total, cur, idx) => {
      const val = cur[0] + "=" + cur[1];
      if (idx === Object.entries(params).length - 1) {
        return total + val;
      } else {
        return total + val + "&";
      }
    }, "")
  );
};

2.3生成逻辑

接下来就是编写生成逻辑了

const path = require("path");

module.exports = (ctx, options) => {
 ctx.registerCommand({
    // 命令名
    name: "generate-router-methods",
    async fn() {
      console.log("开始生成");
      const appConfigPath = ctx.helper.resolveMainFilePath(
        path.resolve(ctx.paths.sourcePath, "./app.config")
      );
      const appConfig = ctx.helper.readConfig(appConfigPath);
      let pagePath = [...appConfig.pages.map((page) => `/${page}`)];
      //下面是根据官网的分包策略来写的的逻辑,你也可以根据自己的分包方式来编写不同的逻辑
      if (appConfig.subPackages) {
        appConfig.subPackages.forEach((package) => {
          package.pages.forEach((packagePage) => {
            pagePath.push(`/${package.root}/${packagePage}`);
          });
        });
      }
      // console.log(appConfig);
      console.log(pagePath);
      ctx.helper.fs.writeFile(
        ctx.paths.sourcePath + "/utils/toRouterPage.ts",
        generateToRouterMethods(pagePath),
        function (err) {
          console.log(`生成--路由函数(${pagePath.length}个)`);
          if (err) {
            throw err;
          }
        }
      );
    },
  });
};

function generateToRouterMethods(pagePath) {
  const staticStr = `模板内容`;
   //根据自己的模板生成路由方法,可以自定义方法名称。
  const toRouterMethodsStr = pagePath
    .map((item) => {
      const routerSplit = item
        .split("/")
        .map(
          (routerSplitItem) =>
            routerSplitItem.charAt(0).toUpperCase() + routerSplitItem.slice(1)
        );
      let methodName = "";
      if (routerSplit.length > 4) {
        methodName = routerSplit[1] + routerSplit[3];
      } else {
        methodName = routerSplit[2];
      }
      return `
export const to${
        methodName.charAt(0).toUpperCase() + methodName.slice(1)
      }Page = <P>(option?: ToRouterType<P>) => {
  navigateType("${item}", option);
};
`;
    })
    .join("\n");

  return staticStr + toRouterMethodsStr;
}

然后在控制台执行 taro generate-router-methods即可生成函数