PDF 生成模板编辑器
开源可视化 PDF 生成引擎,支持自定义模板,并提供面向开发者的 API,灵活构建文档生成流程。
Web 平台的自定义 UI,很重要的一个部分是对导航栏的自定义。对导航栏进行自定义,您可能会用到几个操作,比如:
ComPDF for Web 的 WebViewer UI 由模块化组件(Header、功能区组、工具分组和按钮)组成,并提供了灵活的 API 来轻松自定义导航栏。
要了解导航栏的结构和不同类型的工具项,您可以阅读本章节的导航栏组成和导航栏工具项部分。您也可以直接跳到示例部分,查看自定义导航栏的示例。
导航栏主要分成三个部分:导航工具、功能区和对应功能的二级菜单栏(包含子工具栏)。
导航工具: 下图(导航栏)左右两侧的图标按钮属于导航工具。它们是顶部 Header default-top-header 中的项,例如 leftPanelButton、fullscreenButton、panToolButton、zoom-container、snippingToolButton、searchPanelToggle 和 menuButton。

功能区: 在导航栏中间、框内的部分,称为功能区(如下图所示)。每个功能都有不同的二级菜单栏。不论是功能区还是二级菜单栏的按钮,都是可以单独修改的。功能区是功能区组 default-ribbon-group,其中每个功能是一个功能区项,其 dataElement 即对应的工具栏分组,例如 toolbarGroup-View、toolbarGroup-Annotate、toolbarGroup-Forms、toolbarGroup-Measure、toolbarGroup-FillAndSign、toolbarGroup-Security、toolbarGroup-Redact、toolbarGroup-Compare、toolbarGroup-EditText、toolbarGroup-Document 和 toolbarGroup-Separation。 
二级菜单栏: 在不同的功能区下有其对应的二级菜单栏,二级菜单栏中会显示对应功能的一组工具。ComPDF for Web 提供多种 API 来自定义该二级菜单栏的工具。二级菜单栏显示在 Header tools-header 中,每个二级菜单栏是一个工具分组组件,例如 annotateGroupedItems 和 formsGroupedItems。下面展示的是注释和表单功能的二级菜单栏:


查找导航栏数据元素属性值
要隐藏/显示导航栏元素,首先必须从 DOM 检查器中找到元素的data-element属性。
例如,下图是功能区的 DOM 部分:

我们可以看见它们的data-element值,现在我们可以使用该值来隐藏/显示它。
隐藏/显示导航栏元素
// 隐藏功能区的注释功能按钮。
instance.UI.disableElements('toolbarGroup-Annotate');
// 显示功能区的注释功能按钮。
instance.UI.enableElements('toolbarGroup-Annotate');// 隐藏左侧面板按钮和搜索按钮。
instance.UI.disableElements(['leftPanelButton', 'searchPanelToggle']);
// 显示左侧面板按钮和搜索按钮。
instance.UI.enableElements(['leftPanelButton', 'searchPanelToggle']);可调用setToolbarGroup,来切换功能区中的功能模式。
import ComPDFKitViewer from "@compdfkit_pdf_sdk/webviewer";
const viewer = document.getElementById('webviewer');
ComPDFKitViewer({
path: '/',
initialDoc: 'Your PDF Url',
licenseKey: 'Input your license here'
}, viewer)
.then((instance) => {
// 设置当前选中的功能区。
instance.UI.setToolbarGroup('toolbarGroup-Annotate');
});导航栏工具项是模块化组件。我们可以通过getModularHeader获取 Header,再调用它的setItems方法来添加、删除、移动导航栏的按钮。组件通过instance.UI.Components中的类创建。如果您希望在导航栏添加自定义工具,了解您需要添加的自定义工具是什么类型以及应使用哪些属性非常重要。下面将介绍导航栏工具项的属性和类型。
const { Components } = instance.UI;
instance.UI.getModularHeader('default-top-header').setItems([
new Components.ToolButton({
dataElement: 'panToolButton',
toolName: 'Pan',
}),
new Components.ToggleElementButton({
dataElement: 'searchPanelToggle',
toggleElement: 'searchPanel',
img: 'Search',
}),
new Components.Divider({ dataElement: 'myDivider' }),
new Components.CustomButton({
dataElement: 'myDownloadButton',
label: 'Download',
onClick: () => instance.UI.downloadPdf(),
}),
]);1. 设置 Header
getModularHeader(dataElement)返回 Header 对象,可以调用getItems、setItems、getGroupedItems、setGap、setJustifyContent、setMaxWidth、setMaxHeight和setStyle来对导航工具进行对应的操作。getModularHeaderList()返回所有 Header,包括顶部 Header default-top-header和二级菜单栏 Header tools-header。
// 获取顶部 Header 的所有项。
const items = instance.UI.getModularHeader('default-top-header').getItems();
console.log(items);2. 自定义按钮
自定义按钮可以触发一个操作。点击按钮不会切换选中状态;可通过 isActive 将其显示为选中。其属性包含:
data-element值。它可用于显示/隐藏该元素。Download或Search)、图像的路径、base64 数据或 SVG 字符串。instance.UI.updateElement(dataElement, { isActive })修改。desktop、tablet、mobile 和 small-mobile。const newCustomButton = new instance.UI.Components.CustomButton({
img: 'Search', // 内置图标名称,也可以是图片地址或 SVG 字符串。
label: 'Alert',
onClick: () => {
alert('Hello world!');
},
dataElement: 'alertButton'
});
// 将按钮显示为选中。
instance.UI.updateElement('alertButton', { isActive: true });3. 状态按钮
状态按钮是一个可自定义的按钮。您可以决定它有多少个状态、什么状态是活跃的以及何时更新状态。其属性包含:
states对象的键之一的字符串。activeState,它是states中当前状态的对象。update和activeState。activeState是states中当前状态的对象。修改activeState后调用update()更新按钮,或调用update(nameOfState)切换到另一个状态。update与 onClick 中的相同。data-element的功能按钮。desktop、tablet、mobile 和 small-mobile。示例:
显示计数的状态按钮。当你点击它时,它会将计数器加 1。
const countButton = new instance.UI.Components.StatefulButton({
initialState: 'Count',
states: {
Count: {
number: 1,
getContent: activeState => {
return activeState.number;
},
onClick: (update, activeState) => {
activeState.number += 1;
update();
}
}
},
dataElement: 'countButton'
});显示当前页码的状态按钮。当您单击它时,文档将转到下一页。如果您已经翻到最后一页,文档将转到第一页。
const { documentViewer } = instance.Core;
const nextPageButton = new instance.UI.Components.StatefulButton({
initialState: 'Page',
states: {
Page: {
getContent: () => documentViewer.getCurrentPage(),
onClick: (update) => {
const currentPage = documentViewer.getCurrentPage();
const totalPages = documentViewer.getPageCount();
const atLastPage = currentPage === totalPages;
if (atLastPage) {
documentViewer.setCurrentPage(1);
} else {
documentViewer.setCurrentPage(currentPage + 1);
}
update();
}
}
},
mount: () => {
// 挂载后执行。
console.log('Mounted.');
},
unmount: () => {
// 销毁前执行。
console.log('Destroyed.');
},
dataElement: 'nextPageButton'
});4. 切换元素按钮
切换元素按钮可用来打开/关闭指定的 UI 元素。当 UI 元素打开时,该按钮处于活跃状态。
其属性包含:
data-element值。它可用于显示/隐藏该元素。data-element属性值。Search或Pageset。desktop、tablet、mobile 和 small-mobile。const newToggleButton = new instance.UI.Components.ToggleElementButton({
img: 'Pageset',
toggleElement: 'pageModePanel',
dataElement: 'pageModePanelButton',
hidden: [ 'mobile' ]
});5. 工具按钮
工具按钮是功能模块下的二级菜单栏中的工具。例如,在 Form 功能模式下,自定义一个工具按钮,并指定该工具按钮的工具名为TextFormFieldCreateTool时,即可创建一个文本框的功能按钮。可将您需要自定义的的工具按钮放置在任意位置。当工具被激活时,该按钮处于活跃状态。
属性:
data-element的功能按钮。Pan、AnnotationCreateLine或TextFormFieldCreateTool。TextFieldIcon或LineTool。未设置时使用通过registerTool登记的图标。desktop、tablet、mobile 和 small-mobile。const newToolButton = new instance.UI.Components.ToolButton({
toolName: 'TextFormFieldCreateTool',
img: 'TextFieldIcon',
dataElement: 'textfieldButton'
});6. 间隔器
间隔器是一个grow设置为1的空工具分组,用来占据任何剩余空间的工具。它用于将按钮推到默认标题的每一侧。
间隔器属性包括:
data-element值。[]。1以占据剩余空间。true,使间隔器始终显示。desktop、tablet、mobile 和 small-mobile。const newSpacer = new instance.UI.Components.GroupedItems({
dataElement: 'newSpacer',
items: [],
grow: 1,
alwaysVisible: true,
hidden: [ 'mobile', 'small-mobile' ]
});7. 分隔线
分隔线呈现一个带有一定边距的垂直条来分隔项目组。
分隔线属性包括:
data-element值。desktop、tablet、mobile 和 small-mobile。const newDivider = new instance.UI.Components.Divider({
dataElement: 'newDivider',
hidden: [ 'mobile', 'small-mobile' ]
});添加自定义保存按钮:
const header = instance.UI.getModularHeader('default-top-header');
const mySaveButton = new instance.UI.Components.CustomButton({
dataElement: 'mySaveButton',
img: `<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 1L1 13" stroke="#BABABA" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1 1L13 13" stroke="#BABABA" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>`,
onClick: function() {
instance.UI.downloadPdf();
}
});
header.setItems([...header.getItems(), mySaveButton]);隐藏注释功能区二级菜单栏的文本工具,并将其放至导航栏右侧:
const { Components } = instance.UI;
const annotateItems = instance.UI.getGroupedItems('annotateGroupedItems');
const header = instance.UI.getModularHeader('default-top-header');
// 获取文本工具。
const freetext = annotateItems.items.find(item => item.dataElement === 'freeTextToolButton');
annotateItems.setItems(annotateItems.items.filter(item => item !== freetext));
// 将直线工具和文本工具添加到顶部导航栏。
header.setItems([
...header.getItems(),
new Components.ToolButton({
toolName: 'AnnotationCreateLine',
img: 'LineTool',
dataElement: 'lineButton'
}),
freetext
]);移除导航栏现有按钮, 仅保留功能区:
const header = instance.UI.getModularHeader('default-top-header');
const items = header.getItems().filter(item => item.dataElement === 'default-ribbon-group');
header.setItems(items);底部页码框的显示与隐藏:
// 隐藏底部页码框。
instance.UI.disableElements('page-nav-floating-header');
// 显示底部页码框。
instance.UI.enableElements('page-nav-floating-header');