适用版本:Foxit PDF SDK for Web 11.1 | 适用示例:examples/UIExtension/complete_webViewer/index.html | 文档日期:2026-09-29
一、背景
complete_webViewer 是福昕 Web SDK 提供的功能最完整的示例工程,默认把下载、打印、打开、注释、表单等全部能力一次性呈现出来。实际项目中,绝大多数客户只需要其中一部分:有的要屏蔽下载以防外泄,有的要保留打印入口但按用户等级临时置灰,有的干脆只要一个纯阅读器。
这些需求都指向同一个动作——在 PDF 打开成功后,对 UIExtension 的组件做可见性或可用性控制。本文给出标准做法、可直接复用的代码,以及几个容易踩的坑。
二、先分清两件事:组件名与 CSS 类名
UIExtension 的界面是由一套模板 + 组件树构成的,每个可交互元素在组件树里都有一个 name。所有控制都必须通过 name 进行,而不是通过 CSS 类名。
这两者长得很像,极易混淆,是实践中最常见的错误来源:
| 概念 |
示例 |
用途 |
| 组件名(component name) |
download-file-button |
传给 getComponentByName(),用于控制逻辑 |
| CSS 图标类 |
fv__icon-toolbar-download |
仅用于样式定位,不能作为组件名 |
命名上还有一条规律值得记住:右键菜单类组件名带 fv-- 前缀(如 fv--contextmenu-item-print),工具栏按钮类一般不带前缀(如 download-file-button、print-button)。不要凭 CSS 类名反推组件名。
常用组件名对照表
| 功能 |
组件 name |
归属 |
控制器 |
| 下载 / 另存 |
download-file-button |
核心 UI |
file:DownloadFileController |
| 打印 |
print-button |
print 扩展模块 |
print:ShowPrintDialogController |
| 打开文件(含下拉子项) |
open-file-button-list |
核心 UI |
— |
| 全屏切换 |
fv--toggle-full-screen-button |
full-screen 扩展模块 |
— |
| 右键菜单 – 打印 |
fv--contextmenu-item-print |
print 扩展模块 |
— |
表中列出的是经核实可稳定控制的常用项,并非全部组件。另需说明两点:一是组件名属于 UI 层的实现细节,不同版本之间可能发生调整,若升级后发现失效,请按第七节的方法重新确认,或与福昕技术支持核对;二是复合按钮(如”打开文件”)只需控制其外层组件即可,内部子项会随之隐藏,无需逐个处理。
三、可用 API
以下接口均在 11.1 JavaScript API 中提供,是本文方案的基础:
| 接口 |
说明 |
PDFUI.getComponentByName(name) |
按名称查找组件,返回 Promise |
Component.hide() / Component.show(showParams) |
隐藏 / 显示组件 |
Component.disable() / Component.enable() |
禁用(置灰不可点)/ 启用 |
Component.disabled |
读取当前禁用状态 |
Component.keepState(KeepStateKind.VISIBILITY) |
锁定当前可见性状态 |
Component.revokeKeepState(...) |
解除锁定,交还 SDK 自动控制 |
Component.isStateKept(...) |
查询是否处于锁定状态 |
keepState 系列自 8.5.2 版本起提供,是专门为应用层准备的组件状态管理接口,Web SDK 内部不会调用它,因此应用可以放心地用它接管组件状态。
四、推荐实现
下面这段代码可直接放进 complete_webViewer/index.html,放在 pdfui 实例创建之后:
// ===== 按钮策略配置 =====
// hide : 完全从界面移除
// disable: 保留显示,但置灰、不可点击
var BUTTON_POLICY = {
hide: ['download-file-button'],
disable: ['print-button']
};
function lookup(names) {
return Promise.all(names.map(function (n) {
return pdfui.getComponentByName(n);
}));
}
function applyButtonPolicy() {
return Promise.all([
lookup(BUTTON_POLICY.hide),
lookup(BUTTON_POLICY.disable)
]).then(function (groups) {
groups[0].forEach(function (comp, i) {
if (!comp) {
console.warn('[UI] 组件未找到,请核对名称:', BUTTON_POLICY.hide福昕PDF SDK 软件开发工具包 > 福昕PDF SDK(Web));
return;
}
comp.hide();
comp.keepState(); // ★ 锁定,防止 SDK 自行恢复显示
});
groups[1].forEach(function (comp, i) {
if (!comp) {
console.warn('[UI] 组件未找到,请核对名称:', BUTTON_POLICY.disable福昕PDF SDK 软件开发工具包 > 福昕PDF SDK(Web));
return;
}
comp.disable();
});
});
}
// ===== 执行时机:两处都要 =====
// 1) 组件树就绪后(覆盖打开文档前的状态)
pdfui.getRootComponent().then(applyButtonPolicy);
// 2) 每次文档打开成功后(addon 组件加载较晚,且 SDK 可能重置状态)
pdfui.addViewerEventListener(Events.openFileSuccess, applyButtonPolicy);
需要动态放开限制时:
pdfui.getComponentByName('download-file-button').then(function (comp) {
comp.revokeKeepState(); // 先解锁
comp.show(); // 再显示
});
pdfui.getComponentByName('print-button').then(function (comp) {
comp.enable();
});
五、隐藏与禁用,怎么选
| 诉求 |
做法 |
效果 |
| 彻底不出现,用户无从感知 |
hide() + keepState() |
按钮从 DOM 中移除 |
| 保留入口但当前不可用 |
disable() |
按钮可见、置灰、点击无响应 |
| 按用户等级动态切换 |
两者结合,随状态切换 |
灵活,建议封装成统一函数 |
如果只是想”不显示下载”,hide() + keepState() 是最干净的做法。如果产品上需要让用户知道”有这个功能但没权限”,用 disable() 更合适。
六、几个必须注意的坑
1. hide() 之后必须 keepState()
这是最容易被忽略、也最容易表现为”时灵时不灵”的一点。UIExtension 会在文档打开、权限变更、视图切换等时机,按照内置逻辑重新计算并显示组件。只调用 hide() 而不锁定,按钮往往在换一份文档后就自己冒出来了。
keepState() 的作用正是把可见性状态的控制权从 SDK 手中接管过来。
2. 禁用状态需要在每次打开文档后重新施加
keepState() 目前只管理可见性(KeepStateKind.VISIBILITY),不覆盖禁用状态。因此在切换文档后,disable() 的效果可能丢失。第四节示例代码在 openFileSuccess 中重复执行策略,就是为此。
3. 扩展模块提供的按钮要等模块加载完
print-button 由 print 扩展模块(addon)提供,并非核心 UI 的一部分。示例工程一次性加载全部扩展模块,这类组件的出现时机晚于核心组件。这就是为什么代码中除了 getRootComponent(),还要在 openFileSuccess 里再跑一次——如果只查一次,很可能拿到 undefined。
另外,示例工程采用的是扩展模块整包加载的方式,无法在配置层面单独剔除某个模块。如果确实需要在功能层面裁掉某项能力(而不只是界面隐藏),建议联系福昕技术支持评估定制方案。
4. 前端隐藏不等于安全(重要)
界面上隐藏下载按钮,只是 UI 层的遮挡。以 complete_webViewer 默认的 openPDFByHttpRangeRequest 加载方式为例,分片请求的 URL 在浏览器网络面板中依然可见,有技术手段可以直接还原出原始文件。
如果业务目标是防止文件外泄,必须在服务端解决:不返回原始文件流,改为服务端渲染后下发图片或自绘内容;或者在网关层做鉴权与频控。前端隐藏只能防”误触”,不能防”有意获取”。
5. 按文档权限自动控制
如果 PDF 本身带有权限限制(如禁止打印、禁止复制),SDK 会自动把对应按钮置灰,这一层无需额外代码。
需要覆盖权限计算逻辑时,可在构造 PDFUI 时通过 viewerOptions.customs.getDocPermissions 自定义权限返回值——complete_webViewer 示例工程中已预留了这段配置(默认处于注释状态,取消注释即可启用)。具体签名与返回值含义请以所用版本的官方文档与示例工程为准。
七、如何自行查找任意按钮的组件名
上表只覆盖了常见的几个。项目中要控制其他按钮时,可用以下方法定位:
方法一:浏览器 DevTools 直接查看(最直观)
UIExtension 渲染完成后,界面元素会带有 name 属性。打开浏览器开发者工具,在控制台执行:
document.querySelectorAll('button[name]') // 列出所有带 name 的按钮
配合界面上的图标或悬浮提示文本,即可确认按钮与组件名的对应关系。
方法二:运行时验证
拿到候选名称后,先在控制台确认组件确实存在:
pdfui.getComponentByName('download-file-button').then(c => console.log(c));
返回组件对象说明名称正确;返回 undefined 说明名称有误,或该组件尚未加载完成(参见第六节第 3 点)。
方法三:查阅官方文档或咨询福昕技术支持
组件名属于 UI 层的实现细节,并未在 API 参考中逐一穷举。若需要控制的按钮较多、或涉及右键菜单、侧边栏等复合组件,建议直接联系福昕技术支持获取对应版本的组件清单,避免逐个试错。
八、小结
控制 UIExtension 功能按钮的核心是三步:找准组件名 → 用 hide()/disable() 施加策略 → 用 keepState() 锁定并在每次打开文档后重新施加。整个链路全部走官方组件 API,不依赖任何界面结构的临时改动,升级 SDK 时的兼容性风险最低。
界面层面的控制到此为止;涉及文件安全的诉求,请务必回到服务端方案上解决。
信息来源:本文接口清单取自 Foxit PDF SDK for Web 11.1 JavaScript API 参考;组件名依据 11.1 版本组件定义整理;keepState 系列用法参考福昕官方知识库(support.fuxinsoft.cn)。接口签名与组件名的细节以所用版本的官方文档为准。