WPS JSA 宏编程(JS):1.初识
一、簡介
從 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 宏編輯器只提供了一個入口來編寫事,即
它訂閱了當前工作簿 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 不內建任何模塊,用戶想要訂閱事件,直接在事件欄里面選中即可,事件處理程序名稱與參數,會更好地協助你做你想做的事兒。
四、用戶窗體
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('
');
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 好破浪(乘涼)
總結
以上是生活随笔為你收集整理的WPS JSA 宏编程(JS):1.初识的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在石家庄买了一个loft,请问装修该注意
- 下一篇: 如果开发商降价卖房,我们要怎么办呢?