程序员必知:WPSJSA宏编程(JS):1.初识

简介: 程序员必知:WPSJSA宏编程(JS):1.初识

一、简介

从 WPS 2021 版本开始,WPS 正式支持使用 JS 作为宏语言,官方称 JSA(报错时,用得就是这个名称),亦即 JS for Application 的缩写。

根据官方文档(中的介绍,WPS 内嵌了一个 V8 引擎的 JavaScript 运行时,支持大部分 ES6 语法,实测支持到 ES2019:

WPS宏编辑器集成了一个V8 引擎的 JavaScript 运行时,支持大部分ES6语法,因此宏编辑器支持JavaScript 标准内置对象,注意,JS内置对象和浏览器的内置对象是不同的,WPS宏编辑器集成的是JavaScript 运行时,而不是浏览器,因此WPS宏编辑器不支持浏览器的内置对象。具体API参见 。

JSA 也是 WPS 默认的宏语言,WPS 官方为之提供了 WPS 宏编辑器,以方便大家编辑 JSA 宏代码。

二、宏录制

如下示例是要给 B4 单元格字体颜色设为红色,背景色设置为黄色,录制的宏代码如下:

1 /*

2 Macro1 Macro

3 宏由 nutix 录制,时间: 2021/07/17

4 /

5 function Macro1()

6 {

7 Range("B4").Select();

8 (obj=>{

9 obj.Color = 255;

10 obj.TintAndShade = 0;

11 })(Selection.Font);

12 (obj=>{

13 obj.Pattern = xlPatternSolid;

14 obj.Color = 65535;

15 obj.TintAndShade = 0;

16 obj.PatternColorIndex = -4105;

17 })(Selection.Interior);

18

19 }

第 8-11 和 第 12-17 行处的代码段,是定义箭头函数,以及对它们的调用。

宏录制器,总是会把对同一个对象的多个操作,以这种箭头函数的形式,录制出来。

这是复合写法,手工写 JSA 宏代码,肯定是不提倡这种写法的。

三、事件

这可能是大家打交道最频繁的,与 VBA 有所不同的是,现在没有文档模块了,WPS 宏编辑器只提供了一个入口来编写事,即

它订阅了当前工作簿 Workbook 的 SheetChange 事件,当第 1/2 表的第 4 列的值发生改变时,将单元格的字体颜色修改为蓝色,它的代码如下:

1 function Workbook_SheetChange(Sh, rg)

2 {

3 if (【1, 2】.indexOf(Sh.Index) != -1) {

4 //对第1、2表D列的单元格值变更进行处理

5 const blue = 12611584;

6 if (rg.Column == 4) {//代码效果参考:http://www.zidongmutanji.com/bxxx/333304.html

7 rg.Font.Color = blue;

8 }

9 }

10 }

与 VBA 的事件有所不同,WPS 中不内建文档模块,这里说的文档模块,就是你在 Office 的 VBE 中【工程管理器】里面的 Sheet1, Sheet2, ..., SheetN 和 ThisWorkbook,这 N+1 个内建的模块,VBE 里针对每一个打开的工作簿,都会内建一堆这样的文档模块,工作表及打开的工作簿如果比较多时,要查找自己的模块,还得去拖滚动条。

WPS 则以比较巧妙的方式,规避了这个问题:WPS 不内建任何模块,用户想要订阅事件,直接在事件栏里面选中即可,事件处理程序名称与参数,会更好地协助你做你想做的事儿。

四、用户窗体

WPS贴心地为大家新提供了几个控件,尤其是【水平布局控件】和【垂直布局控件】,有这两个控件,大家可以更好的设计窗体了。

要编写窗体及其控件的事件,和文档事件一样,通过事件栏,来指定要处理的控件的事件

由图可见WPS窗体的界面与代码是分离的,代码是写在普通模块里面的,绘制的窗体是在另一个模块

由上图可见,所有的对象,无论是Application(应用程序),Workbook(工作簿)、窗体、窗体控件、工作表控件,这些事件源,都是在同一个列表中,大家注意命名,以免混淆

五、自定义公式函数

为表格自定义公式函数是很简单的,只要返回常规类型(如文本,数字,日期,真假值即可),且是全局函数即可

1 /删除给定文本的某字符及后面的字符

2 target : 要处理的目标

3 from : 要删除的起始字符

4 /

5 function DeleteFrom(target, from) {

6 let value;

7 if (target.constructor.name == 'Range') {

8 //本公式只接受一个单元格引用

9 if (target.Areas.Count > 1 ||

10 target.Areas.Item(1).Cells.Count > 1)

11 throw new Error('本函数只能处理一个单元格');

12 else

13 value = target.Value().toString();

14 } else

15 value = target.toString();

16

17 if (from.constructor.name == 'Range') {

18 if (from.Areas.Count > 1 ||

19 from.Areas.Item(1).Cells.Count > 1)

20 throw new Error('当 from 参数是一个单元格' +

21 '引用时,请确保它只包含一个单元格');

22 from = from.Value().toString();

23 }

24 else

25 from = from.toString();

26

27

28 let index = value.indexOf(from);

29 if (index == -1)

30 return value;

31 else

32 return value.substr(0, index);

33 }

34

35 /将单元格区域数据转换成一个基于文本的表

36 target : 要处理的单元格区域

37 sep : 分隔符

38 /

39 function ToTextTable(target, sep = ',') {

40 if (target.constructor.name != 'Range')

41 throw new TypeError('target 参数必须是一个单元格区域');

42

43 sep = sep.toString();

44 let values = new Array();

45 for (let iRow = 1; iRow <= target.Rows.Count; iRow++) {

46 let rowValues = new Array();

47 for (let iColumn = 1; iColumn <= target.Columns.Count; iColumn++) {

48 rowValues.push(target.Cells.Item(iRow, iColumn).Value());

49 }

50 values.push(rowValues.join(sep));

51 }

52 return values.join('\n');

53 }

六、WPS宏编辑器与代码调试

WPS 宏编辑器,提供了【立即窗口】,您可以直接在【立即窗口】执行单行的 JSA 语句,就像在写命令行,与 VBA 不同的时,这里不需要前置问号才算求值

WPS 宏编辑器,允许你为 JSA 代码行设置断点,以方便对代码的调试,配套提供了【本地窗口】,以方便你了解断点处的运行状态

WPS 宏编辑器,同样提供了【逐语句】【逐过程】【跳出】功能,您可以以 VBA 熟悉的方式来调试 JSA 代码,不同的是它们的快捷键与 VBA 不同,与现在主流的 IDE 相同

WPS 宏编辑器,同样提供了【编译】工具,你可以在写完代码后,用它来做语法检查

WPS 宏编辑器,同样提供了【监视】功能,并配套提供了【监视窗口】,你可以借此设置中断条件,以进行复杂调试

可以通过【文件】》【导入/出】,来导入/出代码模块

可以在代码行通过:右键》【切换书签】的方式,来建立书签,使用 Ctrl + Shift + N(Next:下一个)/P(Previous:前一个)快捷键,快速地在多个书签之间跳转,这对于调用自定义的库来实现具体应用时比较有用,可以方便地在库与调用代码之间来回切换,调整库代码与应用代码,以便可以有更可靠更高效的代码逻辑

通过【插入】》【文件】,可以在光标所在处快速插入外部文件中的代码或数据

Console 对象是 JS 调试时的重要工具,JSA 环境下的 Console 是指向立即窗口的,你可以通过 Console.log(text) 向立即窗口写数据,也可以通过 Console.clear() 清除它的内容,这控制力比 VBE 强多了

Debug 对象,可以通过 Debug.GC(),要求引擎进行变量垃圾回收;通过 Debug.Print(...) 实现与 Console.log(text) 相同的功能

七、对象成员访问方式上的一些变动

有参数的属性,在 JSA 中变成了方法,须得在后面加 "()" ,才能正确访问,比如 Address 在 VBA 中是属性,因为 VBA 支持带参数的属性,但 JSA 不支持,所以在 JSA 中 Address 成员,被识别为方法,必须以执行函数的方式来访问;当你参考 Office 文档来写 JSA 代码时,要注意,只要需要传递参数,即便手册说它是属性,在 JSA 中也应被当然方法来对待。

VBA 中方法和属性不使用参数时,括号是可以省略的,比如 Worksheet.OLEObjects(...) 方法,VBA 中得到 OLEObjects 集合的方式是 Set objs = Sheet1.OLEObjects ,不加括号,可以正确访问;但 JSA 中必须加括号才能访问,即应写成 let objs = Worksheets.Item('Sheet1').OLEObjects();

VBA 调用方法或有参属性时,如果某个参数有默认值,可以直接省略该位置的参数,比如 ActiveCell.Address(,,xlR1C1),JSA 中不允许这么做,如果想使用默认值,则应写成 ActiveCell.Address(undefined, undefined, xlR1C1)

VBA 可以以命名参数的方式,向方法或属性传递参数,如 ActiveCell.Address(ReferenceStyle:=xlR1C1),这种语法在 JSA 中是不支持的,你必须写成 ActiveCell.Address(undefined, undefined, xlR1C1);

当参数比较多,你又只想传递一个参数,其它都用默认值的时候,怎么办呢,可以这样:ActiveCell.Address(...【,,xlR1C1】);

可能你又要说,如果参数几十个,只想传递某个参数呢?也可以,比如 ThisWorkbook.SaveAs(/有 12 个参数/),每个参数都有默认值,我们想传递第 9 个参数,也即 AddToMru 参数,可以这样写:

1 function Save() {

2 let args = 【】;

3 args【8】 = true;

4 ThisWorkbook.SaveAs(...args);

5 }

八、JSA 相较于 VBA 的优势

JSA 基于原型链的面向对象,灵活性非常强,但毕竟动态一时爽,重构火葬场,其工程性差,好在它所面临的业务 99.99% 的场景,是弱工程性的,所以正好适用

JSA 背靠 JS,后者有国际性的标准化组织,每年推动语言改进,JS 只会越来越强大,越来越方便,经典 class 的引入就是明证

JSA 背靠 JS,后者有最活跃的社区,由全球人才发力,各种工具与库层出不穷,可以为 JSA 提供助力,比如我使用了来自 github 的 linq.js 库,它极大地方便了一些查询工作

VBA 长久没有语言层面的更新,语言特性早已过时;而现行的 VBA 标准,其语言 特性呆板、生硬,基本没什么灵活性,比如不能愉快地相互传递函数,来灵活地配置功能(借助奇技淫巧曲线救国的,一边去)

VBE 宏编辑器,长久没有得到更新,编程体验奇差:

在编辑的模块窗口是 MDI 窗口模式,而不是便利的标签页模式,关闭与切换都很麻烦

标识符命名具有穿透性,写得好好的库 API 命名,会因为其它模块同名标识符的大小写,被自动修改,真是日了狗了

Excel 表格太多时,工程管理器里面内建的文档模块能排到“天边”

JSA 安全性好,没有对乱七八糟的外部库的支持,你做好 Office 自动化这个本职工作就好,调用 Win32API?,你想干嘛

JSA 跨平台,JS 能跨,JSA 就能跨,基于 V8 好破浪(乘凉)

相关文章
|
5天前
|
Web App开发 JavaScript 前端开发
程序员必知:【three.js练习程序】创建地球贴图
程序员必知:【three.js练习程序】创建地球贴图
14 0
|
2天前
|
人工智能 JavaScript 前端开发
JavaScript AI 编程助手
JavaScript AI 编程助手
10 0
|
3天前
|
缓存 JavaScript 前端开发
老程序员分享:js刷新页面得重新加载和页面的刷新
老程序员分享:js刷新页面得重新加载和页面的刷新
|
3天前
|
缓存 JavaScript 前端开发
程序员必知:广告等第三方应用嵌入到web页面方案之使用js片段
程序员必知:广告等第三方应用嵌入到web页面方案之使用js片段
|
3天前
|
JavaScript 程序员 索引
老程序员分享:JS基础知识(正则)
老程序员分享:JS基础知识(正则)
|
4天前
|
JavaScript 前端开发 小程序
老程序员分享:js中自然日的计算
老程序员分享:js中自然日的计算
|
4天前
|
JavaScript 程序员
老程序员分享:JS日期格式转换
老程序员分享:JS日期格式转换
|
4天前
|
JavaScript 程序员
老程序员分享:js实现复选框的全选、全部选和反选
老程序员分享:js实现复选框的全选、全部选和反选
|
4天前
|
JavaScript 前端开发 IDE
程序员必知:WPSJSA宏编程(JS):1.初识
程序员必知:WPSJSA宏编程(JS):1.初识
|
Web App开发 JavaScript 前端开发