wps - 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 宏編輯器只提供了一個入口來編寫事,即

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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM