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)
大部分属性和方法名一样,枚举常数也通用(wdAlignParagraphCenter、wdCaptionPositionBelow 都能直接用)。
关键差异
| 项目 | VBA | JS 宏 |
|---|---|---|
| 数组索引 | 默认 1-based | 0-based(JS 原生) |
| 可选参数 | 可省略或用命名参数 := |
不支持命名参数,用 undefined 占位 |
| 类型系统 | Variant,自动转换 | JS 弱类型,COM 边界需显式处理 |
| Windows API | Declare Function 直接调 |
不支持直接调,通过 ActiveXObject 或 Run("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 代码。
测试了三组:
- 空文档 +
wps.Run('Eval', 'Application.ActiveDocument.Content.Text = "xxx"')→-2147352567 发生意外 - 打开 VBA
.docm后调用 → 同样的错误 wps.Application.Run('Eval', '1+1')→ 同样的错误
根因: Run("Eval") 是 JS 宏编辑器内部用来调 COM 对象的通道(JS 调外部世界),不是 COM 反向调 JS 的通道(外部世界调 JS 宏)。V8 引擎不暴露 COM 接口,从 Python/win32com 链路进不去。
这意味着:
- Python 能驱动 VBA(
wps.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_Click、chicunduotu_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 边界决定的。但可以通过文档属性桥/剪贴板桥/文件监控桥间接通信。
最佳策略:
- 自己开发/维护时用 VBA(生态好、查资料方便)+ Python COM 桥接(需要 AI 判断时)
- 分发时同时提供 JS 宏版本(核心功能版本,砍掉 Ribbon 用文档内按钮)
- Ribbon 界面暂时放弃,等 WPS 开放平台的 JS 宏 Ribbon 支持成熟了再补
迁移优先级建议:
- 第一批(立即):插文号、插表号、插图号、图片居中——最常用、最简单
- 第二批:表格样式批量设置、自动编号转文本——高频但稍复杂
- 第三批:地名检查、叠词检查——需要处理 Find 的参数坑
- 最后:Ribbon UI 相关——需要重新设计交互方案