1.前言
官方文档中对于这部分内容介绍比较少,从我能够为了这部分内容单独开一章就可以看出,我认为这部分内容非常重要。我们平时测试功能可以将所有代码写在一个文件中,但是真正的脚本开发过程中,会有ui页面代码和逻辑代码,一般情况下会分成两个或者多个文件。在autojs中,一个程序只能有个主入口,其他部分的代码可以看做成模块。模块整体架构类似于树形,但是又有所不同,主入口相当于数据根,然后其他模块直接或者间接连接在树根主入口程序上。了解树形结构的都知道,树形中不能出现环,在模块上可以理解为,A模块引入了B模块,B模块就不能引入A模块了。在树形中,每个节点只允许一个父级,但是在模块引入过程中,一个节点可以允许多个父级。这就是为什么我说模块整体架构类似于树形,又有所不同。
但是有种特殊情况,A模块会用到B模块的内容,B模块中又会用到A模块的部分内容,这个怎么办?其实有很多种方式:方式一,直接复制所需A模块的内容粘贴到B模块一份;方式二,新建一个C模块存放A模块和B模块的公共部分,然后A模块和B模块均引入C模块;方式三,将所需A模块的内容加到全局中,B模块通过调用全局来使用。
这三种方式有各自的使用场景:如果公共部分比较少,并且使用模块也比较少,退浆使用方式一;如果公共部分比较多,并且使用的模块比较多,推荐使用方式二;如果脚本开发已经基本完成,增加部分功能时,用到了公共部分,推荐使用方式三。
我们可以看出:方式一是最笨的一种方式,会导致代码冗余,但是执行效率反而最高;方式二是最正式的处理公共部分的方式,但是使用过多反而会影响执行效率,增加代码阅读难度;方式三是一种介于两者之间的方式,在不改变架构的情况下完成功能,但是使用过多会占用大量内存。
上面只是介绍各种方式的优缺点,真正使用过程中,使用哪种方式都不影响,那种“使用过多”触发的缺点,很难出现,大家可以放心使用。我后期会做一个插件,这个插件其实就是类似于方式二,当然也可以在主程序中将插件通过方式三加载到全局,方便后面直接使用。
2.多模块引入
1.概况
为了重现方式二,我们可以设定三个模块,分别为模块A、模块B、模块C。其中模块A为主程序入口,模块A引入模块B和模块C,模块B又进入模块C。执行代码之前,需要先将所有模块和配置文件保存到设备,然后就能通过编辑器启动了。
各文件整体架构如下:
2.主程序配置
在项目根目录中创建“project.json”文件,并且将主程序设置为A模块。需要特别注意,配置文件中不要加注释内容,否则无法解析。
{
"name": "CSDN辅助",
"main": "A.js",
"launchConfig": {
"hideLogs": false,
"displaySplash": true
},
"ignore": [
"build"
],
"packageName": "com.py.csdn",
"versionName": "1.0.0",
"versionCode": 1
}
3.A模块
在文件系统部分已经介绍了相对路径兼容性代码,在A模块中已经使用。我们可以将最终的relativeFolder变量保存到全局中,在其他模块可以直接使用这个变量,这样设置可以保证只需要改主程序的环境文件夹,就可以做到整个脚本自动切换。我再次提醒下,涉及到文件读取或者加载都得先保存代码到设备,然后才能成功运行。
// 生产环境相对路径文件夹
let procRelativeFolder = "./";
// 项目名称,根据实际情况替换
let projectName = "模块";
// 开发环境相对路径文件夹
let devRelativeFolder = files.cwd() + "/" + projectName + "/";
// 相对路径文件夹
// 开发时,切换到开发环境
// 打包时,切换到生产环境
// 读取相对路径文件时,都采用这种方式
// 为了实现编辑器能够直接运行,切换为开发环境
let relativeFolder = devRelativeFolder;
// 将相对文件路径保存到全局,方便其他模块使用
global.relativeFolder = relativeFolder;
// 引入B模块
let bObj = require(relativeFolder + "B.js");
bObj.log("A模块调用");
// 引入C模块
let cObj = require(relativeFolder + "C.js");
cObj.log("A模块调用");
// 删除全局自定义变量
delete global.relativeFolder;
4.B模块
// 获取相对路径文件夹
let relativeFolder = global.relativeFolder;
// 引入C模块
let cObj = require(relativeFolder + "C.js");
cObj.log("B模块调用");
// 设置模块对象
let bObj = {};
bObj.log = function (msg) {
console.log("这里是B模块,打印为:" + msg);
}
// 导出模块对象
module.exports = bObj;
5.C模块
// 设置模块对象
let cObj = {};
cObj.log = function (msg) {
console.log("这里是C模块,打印为:" + msg);
}
// 导出模块对象
module.exports = cObj;
6.控制台打印
保存项目到设备后,在A模块直接运行代码,显示以下信息。如果理解了这个打印顺序和三个模块之间的关系,以后可以自己灵活设置自己的模块。
3.全局引入
1.概况
我后面会封装一个pyGlobal的插件,下面会以这个插件为例,介绍下如何全局引入,后面再如何使用。为了减少文件,在A模块已经测试“多模块引入”的基础上,引入pyGlobal插件,并且引入D模块。A模块调用D模块的函数,在这个函数中,D模块调用全局的插件函数。
整体结构如下,插件内容就不提供了,知道调用了插件里面一个函数即可。
2.A模块
// 生产环境相对路径文件夹
let procRelativeFolder = "./";
// 项目名称,根据实际情况替换
let projectName = "模块";
// 开发环境相对路径文件夹
let devRelativeFolder = files.cwd() + "/" + projectName + "/";
// 相对路径文件夹
// 开发时,切换到开发环境
// 打包时,切换到生产环境
// 读取相对路径文件时,都采用这种方式
// 为了实现编辑器能够直接运行,切换为开发环境
let relativeFolder = devRelativeFolder;
// 将相对文件路径保存到全局,方便其他模块使用
global.relativeFolder = relativeFolder;
// 引入B模块
let bObj = require(relativeFolder + "B.js");
bObj.log("A模块调用");
// 引入C模块
let cObj = require(relativeFolder + "C.js");
cObj.log("A模块调用");
// 引入插件
let pyGlobal = require(relativeFolder + "pyGlobal.js");
//将插件引入全局
global.pyGlobal = pyGlobal;
// 引入D模块
let dObj = require(relativeFolder + "D.js");
dObj.getCurrentTime();
// 删除全局自定义变量
delete global.relativeFolder;
delete global.pyGlobal;
3.D模块
// 从全局中获取插件
let pyGlobal = global.pyGlobal;
// 设置模块对象
let dObj = {};
dObj.getCurrentTime = function () {
let currentTime = pyGlobal.getCurrentTime();
console.log("这里是D模块,当前时间戳为:" + currentTime);
}
// 导出模块对象
module.exports = dObj;
4.控制台打印
4.总结
特别注意,只有通过个人主页博客或者个人介绍中方式,才能获取源码