WPS JS宏——零安装分发的唯一解,以及从VBA迁移的全量评估


WPS JS 宏——零安装分发的唯一解

问题

我的工具箱是 VBA 写的(.docm,含 Ribbon 按钮 + 18 个实用宏)。在 WPS 专业版 + 装了 VBA 插件的情况下能用。但发给没装 VBA 环境的同事/客户,打不开。

WPS 个人版没有 VBA 环境,需要额外装 VBA for WPS。而这个插件不是官方一键安装的——很多用户直接放弃。

JS 宏(JSA)是唯一零安装方案。 WPS 2021 起内嵌 V8 引擎,原生自带,任何 WPS 都能跑。


对象模型:90% 通用

WPS JS 宏的 API 模型基本照搬 VBA 的对象层次:

VBA:                   JS:
Application            Application
  .ActiveDocument        .ActiveDocument
  .Selection             .Selection
  .Documents             .Documents
  .Run("宏名")           Application.Run("Eval", jsCode)

大部分属性和方法名一样,枚举常数也通用(wdAlignParagraphCenterwdCaptionPositionBelow 都能直接用)。

关键差异

项目 VBA JS 宏
数组索引 默认 1-based 0-based(JS 原生)
可选参数 可省略或用命名参数 := 不支持命名参数,用 undefined 占位
类型系统 Variant,自动转换 JS 弱类型,COM 边界需显式处理
Windows API Declare Function 直接调 不支持直接调,通过 ActiveXObjectRun("Eval")
文件 I/O Open / Dir 等内置 Dir()(WPS 提供),或 ActiveXObject("Scripting.FileSystemObject")
宏录制 完整支持 支持(WPS 自带录制器)
调试器 VBA IDE 独立宏编辑器(V8 调试器,类似 VS Code)

枚举占位坑

VBA 中可以直接写 Selection.Find.Execute("关键词"),JS 必须用 undefined 填满不用的参数位:

// VBA:
Selection.Find.Execute FindText:="关键词"

// WPS JS:
Selection.Find.Execute("关键词", undefined, undefined, undefined, 
    undefined, undefined, undefined, undefined, undefined, undefined,
    undefined, undefined, undefined, undefined, undefined);

这是 WPS JS 宏最大的写法痛点。


事件:跟 VBA 一样完整

WPS JS 宏在 Word 中的事件覆盖基本等效:

function Application_DocumentOpen(doc) {
    // 打开文档时触发
    Console.log("文档已打开: " + doc.Name);
}

function Application_DocumentBeforeClose(doc, cancel) {
    // 关闭前触发,cancel.Value = true 可阻止关闭
    if (!doc.Saved) {
        MsgBox("请先保存文档!");
        cancel.Value = true;
    }
}

function Application_WindowActivate(doc, win) {
    // 切换文档窗口时触发
}

function Application_DocumentChange() {
    // 文档内容变化时触发
}

function Application_Quit() {
    // WPS 退出时触发
}

事件处理函数写在宏编辑器的"工程资源管理器"→"Normal"→"事件"下,或直接放在任意模块中(函数命名规范:Application_事件名)。

这意味着 WPS JS 宏也能做"打开文档自动检查格式""保存时自动备份"这类 VBA 事件驱动的事。


外部调用:Python → WPS → JS 宏

⚠️ 方案 1:COM Run("Eval", ...) —— 实测不可行

2026-06-30 实测结论:wps.Run("Eval", ...) 从外部 COM 无法执行 JS 代码。

测试了三组:

  1. 空文档 + wps.Run('Eval', 'Application.ActiveDocument.Content.Text = "xxx"')-2147352567 发生意外
  2. 打开 VBA .docm 后调用 → 同样的错误
  3. wps.Application.Run('Eval', '1+1') → 同样的错误

根因: Run("Eval") 是 JS 宏编辑器内部用来调 COM 对象的通道(JS 调外部世界),不是 COM 反向调 JS 的通道(外部世界调 JS 宏)。V8 引擎不暴露 COM 接口,从 Python/win32com 链路进不去。

这意味着:

  • Python 能驱动 VBAwps.Run("宏名") ✅)
  • Python 不能驱动 JS 宏wps.Run("Eval", ...) ❌)

这不是配置问题,是设计边界。

变通:三个桥接通道

如果你需要"Python 触发一个已打开的 JS 宏文档做某件事",有三条旁路:

桥 A:文档属性桥(最优雅)

# Python 侧:写入指令
doc.CustomDocumentProperties("_cmd").Value = "插文号"
// JS 宏侧:轮询读取
function 轮询指令() {
    let props = Application.ActiveDocument.CustomDocumentProperties
    try {
        let cmd = props.Item("_cmd").Value
        if (cmd === "插文号") {
            插文号()
            props.Item("_cmd").Value = ""  // 清空
        }
    } catch(e) {}
}
// 用 Application.OnTime 定时执行
Application.OnTime(new Date().getTime() + 500, "轮询指令")

慢但稳定。 适合低频指令触发。

桥 B:剪贴板桥(最轻量)

Python 写剪贴板 → JS 宏快捷键触发 → 读剪贴板解析执行。 零安装,但依赖用户触发快捷键。

桥 C:文件监控桥(最稳定)

Python 写 C:\temp\wps_cmd.json → JS 宏用 ActiveXObject("Scripting.FileSystemObject") 定时扫文件 → 读命令。 需要 JS 宏开着定时器,但最可靠。

方案 2:WPS 加载项 HTTP 桥

WPS 加载项系统(基于 HTML/JS 的插件)在本地起 HTTP 服务,路径是 /transfer/runParam

import requests
requests.post('http://localhost:xxxx/transfer/runParam', json={
    'action': 'runMacro',
    'name': '检查山西省其他地名',
    'args': ['太原市']
})

比 COM 更稳定(不走 COM 协议栈),但需要对方装 .wpsaddon 加载项文件。

方案 3:文件/剪贴板侧通道

跟 VBA 一样,JS 宏也能读写文档属性和剪贴板。Python 写指令到文档自定义属性,JS 宏的定时器或事件扫描到后执行。


工具箱 18 个宏的迁移评估

迁移难度 原因
插文号(正则替换括号) 🟢 轻松 JS 原生正则比 VBA 强,直接重写
插表号/插图号 🟢 轻松 API 一样,改语法即可
设置图片首行不缩进位置居中 🟢 轻松 遍历 InlineShapes,逻辑不变
批量设置表格字体样式 🟢 轻松 Tables 遍历,基本照搬
域代码切换 🟢 轻松 Selection.Fields.ToggleShowCodes()
选中区域自动编号转普通文本 🟢 轻松 ListFormat.ConvertNumbersToText()
添加文本属性 🟢 轻松 CustomDocumentProperties API 通用
删除全部域 🟢 轻松 遍历删除
域转为普通文档 🟢 轻松 Fields.Unlink()
插入多图/多图改尺寸 🟡 中等 文件对话框 API 不同,但 JS 有替代
普通文本编号删除 🟡 中等 Find/Replace + Split 逻辑,语法调整
批量word转pdf 🟡 中等 SaveAs 参数写法不同,需查文档
检查山西省其他地名 🟡 中等 逻辑不变,Find 方法需要 undefined 占位
检查叠词 🟡 中等 同上
查找替换域 🔴 较复杂 InputBox + 循环确认,逻辑重写
plxgy(UserForm) 🔴 较复杂 JS 宏的 UserForm 控件名变化,属性访问不同

工作量估计: 前 14 个宏一天能搬完,后 4 个涉及 UI 的需要重新设计交互。


Ribbon 的问题(最大分歧点)

VBA 工具箱用 CustomUI XML 实现 Ribbon 按钮——plxgy_Clickchicunduotu_Click 这些回调。

WPS JS 宏不支持 CustomUI XML。

Ribbon 自定义在 JS 宏下有两条路:

路 1:WPS 加载项(重武器)

wpsjs npm 包开发加载项,基于 HTML/CSS/JS 的 web 技术栈。打包成 .wpsaddon 分发。

  • 优点:UI 灵活,能做任何界面
  • 缺点:需要 Node.js 开发环境,分发仍是额外文件

路 2:砍掉 Ribbon,用快捷键 + 文档内按钮(推荐)

WPS JS 宏支持在文档内插入 ActiveX 命令按钮(CommandButton),用户点按钮触发宏。也可以通过 Application.OnKey 绑定快捷键。

  • 优点:零配置,文档自包含
  • 缺点:不如 Ribbon 直观

第三种思路: 把常用的 5-6 个宏放到快速访问工具栏(QAT),其余放在文档内按钮区。QAT 配置保存在文档里,用户打开就能看到。


分发策略对比

方案 对方需要什么 适用场景
VBA .docm WPS 专业版 + VBA 插件 自己用 / 同事都有 VBA 环境
JS 宏 .docm 无(WPS 原生支持) 发给任何人
WPS 加载项 .wpsaddon 安装加载项文件 组织级分发,有 IT 支持
Python + MCP Python + word-mcp-live + pywin32 自己用,需要 AI 能力
Python → VBA pywin32 wps.Run("宏名") 自己用,Python 发令 VBA 干活 ✅

总结

VBA 的优势不在语法,在生态—— 几十年的 StackOverflow 答案、CustomUI XML、Win32 API 桥接。这些 WPS JS 宏目前做不到或做不好。

JS 宏的优势在分发。 零安装,任何 WPS 都能跑。这是国产业务环境下无法忽视的优势——你的工具要发给县局、乡镇、其他单位,对方不可能为了一个模板去装 VBA 插件。

Python 不能驱动 JS 宏。 这是 COM 边界决定的。但可以通过文档属性桥/剪贴板桥/文件监控桥间接通信。

最佳策略:

  1. 自己开发/维护时用 VBA(生态好、查资料方便)+ Python COM 桥接(需要 AI 判断时)
  2. 分发时同时提供 JS 宏版本(核心功能版本,砍掉 Ribbon 用文档内按钮)
  3. Ribbon 界面暂时放弃,等 WPS 开放平台的 JS 宏 Ribbon 支持成熟了再补

迁移优先级建议:

  • 第一批(立即):插文号、插表号、插图号、图片居中——最常用、最简单
  • 第二批:表格样式批量设置、自动编号转文本——高频但稍复杂
  • 第三批:地名检查、叠词检查——需要处理 Find 的参数坑
  • 最后:Ribbon UI 相关——需要重新设计交互方案

文章作者: 摸鱼
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 摸鱼 !
  目录