首页
/ ToolJet PDF 组件完全实践指南:通过 URL 与 Base64 嵌入、缩放控制及下载实现的 PDF 文档展示方案

ToolJet PDF 组件完全实践指南:通过 URL 与 Base64 嵌入、缩放控制及下载实现的 PDF 文档展示方案

2026-09-09 17:48:28作者:温玫谨Lighthearted

本文基于 ToolJet 官方文档 docs/docs/widgets/pdf.md 与前端源码 frontend/src/AppBuilder/Widgets/PDF.jsx、组件配置 frontend/src/AppBuilder/WidgetManager/widgets/pdf.js,系统讲解 ToolJet PDF 组件的嵌入方式(URL / Base64 Data URL)、全部配置属性的源码级默认值、翻页控制与下载功能的底层实现,以及浏览器兼容性边界。读完本文,你可以独立在 ToolJet 应用中嵌入 PDF 文档,理解其渲染管线(react-pdf + pdf.js),并掌握从数据库加载 Base64 编码 PDF 的完整实战链路。

组件概览与渲染管线

PDF 组件用于在 ToolJet 画布中嵌入 PDF 文件,支持两种数据来源:直接提供 PDF 的 URL,或通过 Base64 编码(Data URL 形式)提供文件内容。组件的定位描述为 "Embed PDF documents"(嵌入 PDF 文档),这一点可以从组件注册配置 frontend/src/AppBuilder/WidgetManager/widgets/pdf.js#L1-L5 中确认:

export const pdfConfig = {
  name: 'PDF',
  displayName: 'PDF',
  description: 'Embed PDF documents',
  component: 'PDF',
  // ...
};

从源码结构看,组件的渲染管线由两部分组成:

  1. react-pdffrontend/package.json 中声明版本为 ^10.1.0)提供 <Document><Page> 两个 React 组件,负责 PDF 文档加载与逐页渲染;
  2. pdfjs-dist(固定版本 5.3.93)作为底层 PDF 解析引擎,其 Web Worker 在组件加载时被显式初始化:
// PDF.jsx
import { Document, Page, pdfjs } from 'react-pdf';
// PDF.js v5 worker setup for react-pdf v10: provide a URL string to the worker bundle
pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString();

frontend/src/AppBuilder/Widgets/PDF.jsx#L2-L13。Worker 的引入方式(new URL(..., import.meta.url))对 Webpack 5、Vite 等打包器均兼容,保证了 PDF 解析在独立线程中进行,不阻塞 UI 主线程。

组件默认尺寸为宽 20 网格 × 高 640 像素(defaultSize),并注册于 frontend/src/AppBuilder/_helpers/editorHelpers.js#L90 的懒加载映射中(const PDF = lazy(() => import('@/AppBuilder/Widgets/PDF'))),即按需加载,不影响应用构建体积。

两种嵌入方式:URL 与 Base64 Data URL

方式一:直接填写 File URL

在 Inspector 中找到 File URL 属性(属性键为 url,类型为 code,即支持 {{fx}} 动态表达式),填入 PDF 文件的 URL 即可。组件配置中该属性带有一个默认示例值(Wikipedia 上的示例 PDF),见 frontend/src/AppBuilder/WidgetManager/widgets/pdf.js#L7-L14

url: {
  type: 'code',
  displayName: 'File URL',
  validation: {
    schema: { type: 'string' },
    defaultValue: 'https://upload.wikimedia.org/wikipedia/commons/general.pdf',
  },
},

由于属性类型是 code,URL 可以是动态表达式。例如从查询结果取值:

{{queries.getFiles.data[0].url}}

方式二:Base64 Data URL

文档明确说明:Base64 格式同样受支持,输入必须以 data:application/pdf;base64, 前缀开头,后接 Base64 编码字符串。典型的构造方式是拼接查询返回的 Base64 数据:

{{'data:application/pdf;base64,' + queries.getFiles.data[0].pdf}}

官方 how-to 文档 docs/docs/how-to/loading-image-pdf-from-db.md 给出了完整链路:用 Filepicker 组件上传 PDF(将 Accept file types 设为 {{"pdf/*"}}),通过其暴露变量 {{components.pdfPicker.file[0].base64Data}} 取 Base64 串,写入 ToolJet Database 表(varchar 列),再查询取回后拼成 Data URL 填入 PDF 组件的 File URL 属性。该文档中使用的示例为:

{{'data:pdf;base64,' + queries.getFiles.data[0].pdf}}

提示:文档主页面推荐的 MIME 前缀为 data:application/pdf;base64,;浏览器对 data:pdf;base64, 这类简写前缀也能解析,两者在 Data URL 机制上等价,建议以官方 PDF 组件文档给出的 data:application/pdf;base64, 为准。

组件内部对两种来源不做区分——URL 字符串原样传给 react-pdf 的 <Document file={url}>,见 frontend/src/AppBuilder/Widgets/PDF.jsx#L144-L151。当 url 为空字符串时,组件渲染占位提示 No PDF file specifiedPDF.jsx#L202),便于在调试期发现未配置问题。

核心配置属性详解(含源码级默认值)

文档的 Properties 小节列出了 4 个核心属性;结合 frontend/src/AppBuilder/WidgetManager/widgets/pdf.js#L15-L29 的配置,可以补全每个属性的属性键、控件类型与默认值:

属性(Inspector 显示名) 属性键 类型 默认值 说明
File URL url code 示例 URL(见上) PDF 文件地址;支持 data:application/pdf;base64, 前缀的 Base64 格式
Scale page to width scale toggle true 自动调整 PDF 以铺满组件整个宽度
Show page controls pageControls toggle true 开启后悬停/底部显示上一页、下一页按钮与页码
Show download button showDownloadOption toggle true 显示/隐藏 PDF 组件上的 Download 按钮

其中 Scale page to width 的底层逻辑在渲染函数中可以直接看到(PDF.jsx#L152-L160):开启 scale 时,<Page> 只传 width={width - 12}(组件宽度扣除 12px 边距),高度自适应页面比例,从而让每页横向铺满组件;关闭 scale 时则传固定的 height,按组件高度渲染,页面可能不占满宽度。

<Page
  pageNumber={index + 1}
  width={scale ? width - 12 : undefined}
  height={scale ? undefined : height}
  key={`page_${index + 1}`}
  inputRef={(el) => (pageRef.current[index] = el)}
/>

文档原文中对各属性的描述如下,与源码行为一致:

  • File URL:可在此属性下输入要展示的 PDF 文件 URL;也支持 Base64 格式,输入需加 data:application/pdf;base64, 前缀。
  • Scale page to width:自动将 PDF 调整为填充组件整个宽度。
  • Show page controls:默认情况下,鼠标悬停在 PDF 文件上时,会显示上一页/下一页按钮及页码;该开关可将其打开或关闭。
  • Show the download:PDF 组件上的 Download 按钮允许下载 PDF 文件;默认开启,关闭后从组件上移除 Download 按钮。

翻页控制与页码同步的源码实现

文档说"悬停时显示上一页/下一页按钮与页码",源码进一步揭示了其完整机制(frontend/src/AppBuilder/Widgets/PDF.jsx#L50-L82):

  1. IntersectionObserver 页码感知:组件挂载后为 #pdf-wrapper 内的每个 .react-pdf__Page 节点注册 IntersectionObserverthreshold: 0.7,即页面元素 70% 可见时才认为"进入视口"),当用户滚动容器时,自动把当前页码同步到底部状态栏的 X of N 显示中:
const options = {
  root: document.querySelector('#pdf-wrapper'),
  rootMargin: '0px',
  threshold: 0.7,
};
  1. 按钮翻页:底部控制条包含 (上一页)与 (下一页)两个按钮及 {pageNumber} of {numPages} 页码文本。点击按钮触发 updatePage(offset),通过 pageRef 中缓存的各页 DOM 引用滚动到目标页顶部,并更新 pageNumber 状态;在首页时上一页按钮 disabled,末页时下一页按钮 disabled
const updatePage = useCallback(
  (offset) => {
    const { offsetTop } = pageRef.current[pageNumber + offset - 1];
    documentRef.current.scrollTop = offsetTop;
    setButtonClick(true);
    setPageNumber((prevPageNumber) => (prevPageNumber || 1) + offset);
  },
  [pageNumber]
);
  1. 防抖处理滚动反馈:手动点击翻页按钮后,handleScroll 会将 hasButtonClicked 置位,避免按钮触发的程序化滚动被误判为用户滚动,保证页码显示与交互意图一致(PDF.jsx#L177-L183)。

控制条整体只在 !error && !pageLoading 且(showDownloadOption || pageControls)为真时渲染(PDF.jsx#L204-L209)——即只有当文档加载成功且至少开启了其中一项功能时才出现底部栏;两项都关闭时底部栏完全不显示。

Download 按钮的实现细节

Show download button 开关控制下载按钮显隐,默认开启(defaultValue: truepdf.js#L25-L29)。点击后的实现是标准的 fetch → Blob → Object URL → 虚拟 <a> 触发下载 流程(PDF.jsx#L164-L175):

async function downloadFile(url, pdfName) {
  const pdf = await fetch(url);
  const pdfBlog = await pdf.blob();
  const pdfURL = URL.createObjectURL(pdfBlog);
  const anchor = document.createElement('a');
  anchor.href = pdfURL;
  anchor.download = pdfName;   // 文件名取自组件名(componentName)
  document.body.appendChild(anchor);
  anchor.click();
  document.body.removeChild(anchor);
  URL.revokeObjectURL(pdfURL);
}

两个可留意的实现事实:

  • 下载文件名使用组件名componentName)而非原始 URL 中的文件名,因此建议把 PDF 组件重命名为有业务含义的名称(如 displayPDF),下载产物即为 displayPDF
  • 下载走 fetch,因此对跨域 URL 需要有 CORS 支持,或者使用同域/允许跨域的资源;Base64 Data URL 场景下无跨域问题。

密码保护 PDF 的处理

源码中实现了一套文档未展开但实际存在的能力:针对加密 PDF 的密码提示流程(PDF.jsx#L6-L10PDF.jsx#L97-L121)。组件通过 react-pdf 的 onPassword 回调区分两种原因:

  • NEED_PASSWORD:弹出 prompt('Enter the password to open this PDF file.') 让用户输入密码;
  • INCORRECT_PASSWORD:弹出 prompt('Invalid password. Please try again.') 让用户重试。

若用户直接关闭了密码输入框(password === null),组件进入 "Password prompt closed" 状态并渲染一个 Retry 按钮,点击后重置状态重新走加载流程(PDF.jsx#L123-L143)。此外,url 变化时会自动重置 isPasswordPromptClosed,保证切换文件后密码流程不残留。

通用能力:Tooltip、设备可见性与样式

Tooltip

如需在用户悬停 PDF 组件时显示说明文字,在 Tooltip 属性下输入文本即可(文档 General 小节原文)。

Devices(设备可见性)

配置文件中注册了两个设备切换属性(pdf.js#L35-L38),文档 Devices 小节描述如下:

属性 说明 取值方式
Show on desktop 使组件在桌面视图中可见 可直接拨动开关,或点击 fx 输入逻辑表达式动态控制
Show on mobile 使组件在移动视图中可见 同上

值得注意的默认值:新建组件时 showOnDesktop 默认为 {{true}},而 showOnMobile 默认为 {{false}}pdf.js#L64-L68),即移动端默认不显示,如需移动端可见请显式开启。

Styles(样式)

文档 Styles 小节列出 Visibility:控制组件可见性,可开关拨动或点击 fx 输入逻辑表达式动态配置。源码中 PDF 组件实际还注册了两个样式属性(pdf.js#L40-L62):

属性 属性键 类型 默认值
Visibility visibility toggle true
Border color borderColor colorSwatches var(--cc-weak-border)
Border radius borderRadius numberInput 6

渲染时 visibility 为假直接以 display: none 隐藏外层容器,边框颜色与圆角应用到内层容器(PDF.jsx#L185-L194):

<div style={{ display: visibility ? 'flex' : 'none', width: width - 3, height, boxShadow }} data-cy={dataCy}>
  <div
    className="d-flex position-relative h-100 flex-column"
    style={{
      margin: '0 auto',
      overflow: 'hidden',
      borderRadius: `${borderRadius}px`,
      border: `1px solid ${borderColor}`,
    }}
  >

事件与暴露变量

文档明确说明了两点"空集"事实,组件配置文件与之完全对应(events: {}exposedVariables: {}pdf.js#L39pdf.js#L63):

  • Component Specific Actions (CSA):当前没有实现用于规约或控制该组件的组件专属动作;
  • Exposed Variables:当前该组件没有暴露变量——因此你无法像 Filepicker 那样通过 {{components.xxx.file}} 读取 PDF 组件内部状态,动态交互只能依赖其入参url 等属性的 fx 表达式)与通用事件体系。

浏览器兼容性

文档给出的兼容性矩阵(仅列出官方声明值,以文档为准):

Browser Version
Chrome 92 或更高
Edge 92 或更高
Safari 15.4 或更高
Firefox 90 或更高

文档同时说明:若 PDF 组件被集成到你的应用中,它只会在上述支持的浏览器中渲染。适用前提:这是针对组件运行时浏览器环境的约束,构建/部署环境与编辑器环境不受此表限制;若目标终端用户存在低版本浏览器,应通过 Devices 开关或 Visibility 动态表达式做降级隐藏策略。

实战案例:从数据库加载 Base64 PDF 的完整链路

将本文前面各节串联起来,官方 docs/docs/how-to/loading-image-pdf-from-db.md 给出了"上传 → 存储 → 查询 → 展示"的端到端示例,关键步骤为:

  1. 在 ToolJet Database 建表 testDB,新增 pdfimage 两个 varchar 列;
  2. 拖入两个 Filepicker 组件(imagePickerpdfPicker),将 pdfPickerAccept file types 改为 {{"pdf/*"}}
  3. 新建查询 uploadFiles(ToolJet Database / testDB / Create Row),列值分别写 {{components.pdfPicker.file[0].base64Data}}{{components.imagePicker.file[0].base64Data}}
  4. 新建 Button 组件,配置 On clickRun QueryuploadFiles,点击即把 Base64 串写入数据库;
  5. 新建查询 getFiles(List rows)并开启 Run this query on application load?
  6. 拖入 PDF 组件,在 File URL 中填入:
{{'data:application/pdf;base64,' + queries.getFiles.data[0].pdf}}

该方案的价值在于:PDF 文件不依赖外部静态资源托管,数据随应用数据一起入库,配合组件的 scalepageControlsshowDownloadOption 属性即可完成内部工具中合同、报表、发票等文档的在线预览场景。

关键文件索引

内容 路径
PDF 组件官方文档(本文主体来源) docs/docs/widgets/pdf.md
Base64 图片/PDF 加载实战指南 docs/docs/how-to/loading-image-pdf-from-db.md
组件渲染实现(react-pdf + pdf.js 5.x Worker、翻页、下载、密码提示) frontend/src/AppBuilder/Widgets/PDF.jsx
组件注册配置(属性、默认值、默认尺寸、设备开关、样式) frontend/src/AppBuilder/WidgetManager/widgets/pdf.js
懒加载注册入口 frontend/src/AppBuilder/_helpers/editorHelpers.js#L90
依赖版本(react-pdf ^10.1.0 / pdfjs-dist 5.3.93) frontend/package.json
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
docsdocs
暂无描述
Markdown
899
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
525
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395