编写这个插件的初衷是因为不想跳转到一个页面,每次都要写一遍路由链接,类似于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即可生成函数