Skip to content

PDF 生成模板编辑器

开源可视化 PDF 生成引擎,支持自定义模板,并提供面向开发者的 API,灵活构建文档生成流程。

查看 GitHub

自定义导航栏 ​

Web 平台的自定义 UI,很重要的一个部分是对导航栏的自定义。对导航栏进行自定义,您可能会用到几个操作,比如:

  • 添加自定义保存按钮。
  • 删除导航栏现有工具。
  • 重新排序功能区。
  • 隐藏表单功能区的文本域工具,并将其放至导航栏右侧。

ComPDF for Web 的 WebViewer UI 由模块化组件(Header、功能区组、工具分组和按钮)组成,并提供了灵活的 API 来轻松自定义导航栏。

要了解导航栏的结构和不同类型的工具项,您可以阅读本章节的导航栏组成和导航栏工具项部分。您也可以直接跳到示例部分,查看自定义导航栏的示例。

导航栏组成 ​

导航栏主要分成三个部分:导航工具、功能区和对应功能的二级菜单栏(包含子工具栏)。

  • 导航工具: 下图(导航栏)左右两侧的图标按钮属于导航工具。它们是顶部 Header default-top-header 中的项,例如 leftPanelButton、fullscreenButton、panToolButton、zoom-container、snippingToolButton、searchPanelToggle 和 menuButton。

    navigation-tools

  • 功能区: 在导航栏中间、框内的部分,称为功能区(如下图所示)。每个功能都有不同的二级菜单栏。不论是功能区还是二级菜单栏的按钮,都是可以单独修改的。功能区是功能区组 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。 feature-area

  • 二级菜单栏: 在不同的功能区下有其对应的二级菜单栏,二级菜单栏中会显示对应功能的一组工具。ComPDF for Web 提供多种 API 来自定义该二级菜单栏的工具。二级菜单栏显示在 Header tools-header 中,每个二级菜单栏是一个工具分组组件,例如 annotateGroupedItems 和 formsGroupedItems。下面展示的是注释和表单功能的二级菜单栏:

    sub-menus-annotations

    sub-menus-forms

隐藏/显示导航栏元素 ​

查找导航栏数据元素属性值

要隐藏/显示导航栏元素,首先必须从 DOM 检查器中找到元素的data-element属性。

例如,下图是功能区的 DOM 部分:

How Digital Signatures Work

我们可以看见它们的data-element值,现在我们可以使用该值来隐藏/显示它。

隐藏/显示导航栏元素

  • 隐藏/显示功能区的注释功能按钮:
javascript
// 隐藏功能区的注释功能按钮。
instance.UI.disableElements('toolbarGroup-Annotate');
// 显示功能区的注释功能按钮。
instance.UI.enableElements('toolbarGroup-Annotate');
  • 隐藏/显示多个导航栏元素:
javascript
// 隐藏左侧面板按钮和搜索按钮。
instance.UI.disableElements(['leftPanelButton', 'searchPanelToggle']);
// 显示左侧面板按钮和搜索按钮。
instance.UI.enableElements(['leftPanelButton', 'searchPanelToggle']);

切换功能区 ​

可调用setToolbarGroup,来切换功能区中的功能模式。

javascript
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中的类创建。如果您希望在导航栏添加自定义工具,了解您需要添加的自定义工具是什么类型以及应使用哪些属性非常重要。下面将介绍导航栏工具项的属性和类型。

javascript
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。

javascript
// 获取顶部 Header 的所有项。
const items = instance.UI.getModularHeader('default-top-header').getItems();
console.log(items);

2. 自定义按钮

自定义按钮可以触发一个操作。点击按钮不会切换选中状态;可通过 isActive 将其显示为选中。其属性包含:

  • dataElement(字符串) - 设置按钮元素的data-element值。它可用于显示/隐藏该元素。
  • img(字符串,可选) - 内置图标名称(例如Download或Search)、图像的路径、base64 数据或 SVG 字符串。
  • onClick(函数) - 单击时触发的函数。
  • isActive(布尔值或函数,可选) - 将按钮显示为选中,外观与激活的工具按钮相同。可传布尔值,或返回布尔值的函数。可通过instance.UI.updateElement(dataElement, { isActive })修改。
  • title(字符串,可选) - 按钮的工具提示。
  • label(字符串,可选) - 设置按钮展示的文本。
  • style(对象,可选) - 按钮的内联样式。
  • hidden(字符串数组,可选) - 此选项用于在特定屏幕尺寸下隐藏元素。可接受的字符串包括 desktop、tablet、mobile 和 small-mobile。
javascript
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. 状态按钮

状态按钮是一个可自定义的按钮。您可以决定它有多少个状态、什么状态是活跃的以及何时更新状态。其属性包含:

  • initialState(字符串) - 作为states对象的键之一的字符串。
  • states(对象) - 为此形式的对象:{ nameOfState1: state1, nameOfState2: state2, ... }。states 的属性包括:
    • img(字符串,可选):图像的路径、base64 数据或 SVG 字符串。
    • title(字符串,可选):该状态下按钮的工具提示。
    • getContent(函数,可选):更新状态时调用的函数。如果您不使用此按钮的 img 属性,请定义此属性。getContent 有一个参数activeState,它是states中当前状态的对象。
    • onClick(函数):点击时触发的函数。onClick 有两个参数:update和activeState。activeState是states中当前状态的对象。修改activeState后调用update()更新按钮,或调用update(nameOfState)切换到另一个状态。
    • 您需要的更多属性。
  • mount(函数,可选) - 按钮挂载到 DOM 后调用的函数,参数update与 onClick 中的相同。
  • unmount(函数,可选) - 在按钮从 DOM 卸载之前调用的函数。
  • title(字符串,可选) - 按钮的工具提示。
  • dataElement(字符串) - 它可用于显示/隐藏该data-element的功能按钮。
  • hidden(字符串数组,可选) - 此选项用于在特定屏幕尺寸下隐藏元素。可接受的字符串包括 desktop、tablet、mobile 和 small-mobile。

示例:

显示计数的状态按钮。当你点击它时,它会将计数器加 1。

javascript
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'
});

显示当前页码的状态按钮。当您单击它时,文档将转到下一页。如果您已经翻到最后一页,文档将转到第一页。

javascript
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 元素打开时,该按钮处于活跃状态。

其属性包含:

  • dataElement(字符串) - 设置按钮元素的data-element值。它可用于显示/隐藏该元素。
  • toggleElement(字符串) - 要打开/关闭的 UI 元素的data-element属性值。
  • img(字符串,可选) - 内置图标名称,例如Search或Pageset。
  • title(字符串,可选) - 按钮的工具提示。
  • label(字符串,可选) - 设置按钮展示的文本。
  • hidden(字符串数组,可选) - 此选项用于在特定屏幕尺寸下隐藏元素。可接受的字符串包括 desktop、tablet、mobile 和 small-mobile。
javascript
const newToggleButton = new instance.UI.Components.ToggleElementButton({
  img: 'Pageset',
  toggleElement: 'pageModePanel',
  dataElement: 'pageModePanelButton',
  hidden: [ 'mobile' ]
});

5. 工具按钮

工具按钮是功能模块下的二级菜单栏中的工具。例如,在 Form 功能模式下,自定义一个工具按钮,并指定该工具按钮的工具名为TextFormFieldCreateTool时,即可创建一个文本框的功能按钮。可将您需要自定义的的工具按钮放置在任意位置。当工具被激活时,该按钮处于活跃状态。

属性:

  • dataElement(字符串) - 它可用于显示/隐藏该data-element的功能按钮。
  • toolName(字符串) - 目标工具的名称,例如Pan、AnnotationCreateLine或TextFormFieldCreateTool。
  • img(字符串,可选) - 内置图标名称,例如TextFieldIcon或LineTool。未设置时使用通过registerTool登记的图标。
  • title(字符串,可选) - 按钮的工具提示。
  • label(字符串,可选) - 设置按钮展示的文本。
  • hidden(字符串数组,可选) - 此选项用于在特定屏幕尺寸下隐藏元素。可接受的字符串包括 desktop、tablet、mobile 和 small-mobile。
javascript
const newToolButton = new instance.UI.Components.ToolButton({
  toolName: 'TextFormFieldCreateTool',
  img: 'TextFieldIcon',
  dataElement: 'textfieldButton'
});

6. 间隔器

间隔器是一个grow设置为1的空工具分组,用来占据任何剩余空间的工具。它用于将按钮推到默认标题的每一侧。

间隔器属性包括:

  • dataElement(字符串) - 设置间隔器的data-element值。
  • items(数组) - 必须设置为空数组[]。
  • grow(数字) - 必须设置为1以占据剩余空间。
  • alwaysVisible(布尔值) - 必须设置为true,使间隔器始终显示。
  • hidden(字符串数组,可选) - 此选项用于在特定屏幕尺寸下隐藏元素。可接受的字符串包括 desktop、tablet、mobile 和 small-mobile。
javascript
const newSpacer = new instance.UI.Components.GroupedItems({
  dataElement: 'newSpacer',
  items: [],
  grow: 1,
  alwaysVisible: true,
  hidden: [ 'mobile', 'small-mobile' ]
});

7. 分隔线

分隔线呈现一个带有一定边距的垂直条来分隔项目组。

分隔线属性包括:

  • dataElement(字符串) - 设置分隔线的data-element值。
  • hidden(字符串数组,可选) - 此选项用于在特定屏幕尺寸下隐藏元素。可接受的字符串包括 desktop、tablet、mobile 和 small-mobile。
javascript
const newDivider = new instance.UI.Components.Divider({
  dataElement: 'newDivider',
  hidden: [ 'mobile', 'small-mobile' ]
});

自定义 UI 示例 ​

添加自定义保存按钮:

javascript
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]);

隐藏注释功能区二级菜单栏的文本工具,并将其放至导航栏右侧:

javascript
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
]);

移除导航栏现有按钮, 仅保留功能区:

javascript
const header = instance.UI.getModularHeader('default-top-header');
const items = header.getItems().filter(item => item.dataElement === 'default-ribbon-group');
header.setItems(items);

底部页码框的显示与隐藏:

javascript
// 隐藏底部页码框。
instance.UI.disableElements('page-nav-floating-header');
// 显示底部页码框。
instance.UI.enableElements('page-nav-floating-header');