wps - js 学习1

时间:2024-03-10 22:26:46

一、简介

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

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

WPS宏编辑器集成了一个V8 引擎的 JavaScript 运行时,支持大部分ES6语法,因此宏编辑器支持JavaScript 标准内置对象,注意,JS内置对象和浏览器的内置对象是不同的,WPS宏编辑器集成的是JavaScript 运行时,而不是浏览器,因此WPS宏编辑器不支持浏览器的内置对象具体API参见https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects 。

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 宏编辑器只提供了一个入口来编写事,即

image

它订阅了当前工作簿 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) {
 7             rg.Font.Color = blue;
 8         }
 9     }
10 }
复制代码

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

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

 

四、用户窗体

image

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

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

image

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

image

由上图可见,所有的对象,无论是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宏编辑器与代码调试

  1. WPS 宏编辑器,提供了【立即窗口】,您可以直接在【立即窗口】执行单行的 JSA 语句,就像在写命令行,与 VBA 不同的时,这里不需要前置问号才算求值
  2. WPS 宏编辑器,允许你为 JSA 代码行设置断点,以方便对代码的调试,配套提供了【本地窗口】,以方便你了解断点处的运行状态
  3. WPS 宏编辑器,同样提供了【逐语句】【逐过程】【跳出】功能,您可以以 VBA 熟悉的方式来调试 JSA 代码,不同的是它们的快捷键与 VBA 不同,与现在主流的 IDE 相同
  4. WPS 宏编辑器,同样提供了【编译】工具,你可以在写完代码后,用它来做语法检查
  5. WPS 宏编辑器,同样提供了【监视】功能,并配套提供了【监视窗口】,你可以借此设置中断条件,以进行复杂调试
  6. 可以通过【文件】》【导入/出】,来导入/出代码模块
  7. 可以在代码行通过:右键》【切换书签】的方式,来建立书签,使用 Ctrl + Shift + N(Next:下一个)/P(Previous:前一个)快捷键,快速地在多个书签之间跳转,这对于调用自定义的库来实现具体应用时比较有用,可以方便地在库与调用代码之间来回切换,调整库代码与应用代码,以便可以有更可靠更高效的代码逻辑
  8. 通过【插入】》【文件】,可以在光标所在处快速插入外部文件中的代码或数据
  9. Console 对象是 JS 调试时的重要工具,JSA 环境下的 Console 是指向立即窗口的,你可以通过 Console.log(text) 向立即窗口写数据,也可以通过 Console.clear() 清除它的内容,这控制力比 VBE 强多了
  10. Debug 对象,可以通过 Debug.GC(),要求引擎进行变量垃圾回收;通过 Debug.Print(...) 实现与 Console.log(text) 相同的功能

 

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

  1. 有参数的属性,在 JSA 中变成了方法,须得在后面加 "()" ,才能正确访问,比如 Address 在 VBA 中是属性,因为 VBA 支持带参数的属性,但 JSA 不支持,所以在 JSA 中 Address 成员,被识别为方法,必须以执行函数的方式来访问;当你参考 Office 文档来写 JSA 代码时,要注意,只要需要传递参数,即便手册说它是属性,在 JSA 中也应被当然方法来对待。
  2. VBA 中方法和属性不使用参数时,括号是可以省略的,比如 Worksheet.OLEObjects(...) 方法,VBA 中得到 OLEObjects 集合的方式是 Set objs = Sheet1.OLEObjects ,不加括号,可以正确访问;但 JSA 中必须加括号才能访问,即应写成 let objs = Worksheets.Item(\'Sheet1\').OLEObjects();
  3. VBA 调用方法或有参属性时,如果某个参数有默认值,可以直接省略该位置的参数,比如 ActiveCell.Address(,,xlR1C1),JSA 中不允许这么做,如果想使用默认值,则应写成 ActiveCell.Address(undefined, undefined, xlR1C1)
  4. VBA 可以以命名参数的方式,向方法或属性传递参数,如 ActiveCell.Address(ReferenceStyle:=xlR1C1),这种语法在 JSA 中是不支持的,你必须写成 ActiveCell.Address(undefined, undefined, xlR1C1)
  5. 当参数比较多,你又只想传递一个参数,其它都用默认值的时候,怎么办呢,可以这样:ActiveCell.Address(...[,,xlR1C1])
  6. 可能你又要说,如果参数几十个,只想传递某个参数呢?也可以,比如 ThisWorkbook.SaveAs(/*有 12 个参数*/),每个参数都有默认值,我们想传递第 9 个参数,也即 AddToMru 参数,可以这样写:
    1 function Save() {
    2   let args = [];
    3   args[8] = true;
    4   ThisWorkbook.SaveAs(...args);
    5 }

     

八、JSA 相较于 VBA 的优势

  1. JSA 基于原型链的面向对象,灵活性非常强,但毕竟动态一时爽,重构火葬场,其工程性差,好在它所面临的业务 99.99% 的场景,是弱工程性的,所以正好适用
  2. JSA 背靠 JS,后者有国际性的标准化组织,每年推动语言改进,JS 只会越来越强大,越来越方便,经典 class 的引入就是明证
  3. JSA 背靠 JS,后者有最活跃的社区,由全球人才发力,各种工具与库层出不穷,可以为 JSA 提供助力,比如我使用了来自 github 的 linq.js 库,它极大地方便了一些查询工作
  4. VBA 长久没有语言层面的更新,语言特性早已过时;而现行的 VBA 标准,其语言特性呆板、生硬,基本没什么灵活性,比如不能愉快地相互传递函数,来灵活地配置功能(借助奇技淫巧曲线救国的,一边去)
  5. VBE 宏编辑器,长久没有得到更新,编程体验奇差:
    1. 在编辑的模块窗口是 MDI 窗口模式,而不是便利的标签页模式,关闭与切换都很麻烦
    2. 标识符命名具有穿透性,写得好好的库 API 命名,会因为其它模块同名标识符的大小写,被自动修改,真是日了狗了
    3. Excel 表格太多时,工程管理器里面内建的文档模块能排到“天边”
  1. JSA 安全性好,没有对乱七八糟的外部库的支持,你做好 Office 自动化这个本职工作就好,调用 Win32API?,你想干嘛
  2. JSA 跨平台,JS 能跨,JSA 就能跨,基于 V8 好破浪(乘凉)

本文摘自-WPS JSA 宏编程(JS):1.初识 - nutix - 博客园 (cnblogs.com)