根据我们最近的估计,世界上现有的 PDF 数量已经超过了宇宙中的原子数量(未经外部来源验证),因此很有可能,您时不时会遇到一个或两个 PDF 文档。浏览器在处理 PDF 方面做得相当不错。通常情况下,点击指向 PDF 的链接会在浏览器中打开一个新标签页,并使用自定义 UI 和渲染效果,具体取决于浏览器。以下是在 Edge、Chrome、Firefox 和 Safari 中打开的同一个 PDF 的示例:
正如预期的那样,每个浏览器都对 PDF 文档进行了一些处理,但有一点是始终如一的——所有浏览器都接管了整个视窗来渲染 PDF。虽然这对于为读者提供尽可能多的空间来阅读 PDF 非常有用,但在某些情况下,我们可能希望对 PDF 体验有更多控制权。这就是 Adobe PDF Embed API 的作用。PDF Embed API 是一个免费的 JavaScript 库,它允许您将 PDF 文档与其他内容内联显示,并为您提供对工具 UI、支持注释和事件等的控制权。让我们通过一些示例来了解如何使用该库。
获取密钥
在我们开始之前,您需要注册一个密钥。如果您访问我们的 入门 页面,您会看到一个创建新凭据的链接。

如果您还没有 Adobe 帐户,则需要创建一个。系统会提示您为凭据命名并指定应用程序域。名称并不十分重要,但应用程序域很重要。您获得的密钥将限制在特定域。您只能在此处输入一个域,因此,您可以使用 localhost
作为域来开始,或者如果您想在 CodePen 上尝试,可以使用 cdpn.io
作为域。如果您想在本地和生产环境中使用 API,则可以在控制台中创建多个项目或使用 HOSTS 文件配置。(能够为凭据指定多个域是我们的目标。)

点击可爱的蓝色“创建凭据”按钮,您将获得您的密钥。

如果您好奇并想立即了解 Embed API 的功能,请点击“获取代码示例”,这将带您进入一个交互式在线演示。但由于我们是坚定的程序员,在开始工作之前会先构建自己的编辑器,因此让我们直接深入一个简单的示例。
构建演示
首先,让我们构建一个承载 PDF 的 HTML 页面。我已经是一名 Web 开发人员 20 年了,现在是设计精美 HTML 页面的专家。以下是我设计出来的页面:
<html>
<head></head>
<body>
<h1>Cats are Everything</h1>
<p>
Cats are so incredibly awesome that I feel like
we should talk about them more. Here's a PDF
that talks about how awesome cats are.
</p>
<!-- PDF here! -->
<p>
Did you like that? Was it awesome? I think it was awesome!
</p>
</body>
</html>
当然,我添加了一些 CSS 代码:

说实话,我不知道 Adobe 为什么聘请我担任开发者布道师,因为我显然应该在设计团队工作。无论如何,我们如何将 PDF 放入其中呢?第一步是添加我们的库 SDK:
<script src="https://documentcloud.adobe.com/view-sdk/main.js"></script>
现在我们需要一些 JavaScript 代码。当我们的库加载时,它会触发一个名为 adobe_dc_view_sdk.ready
的事件。根据您加载脚本的方式和您选择的框架,该事件可能会在您有机会检查它之前就触发。
我们也可以检查 window.AdobeDC
是否存在。我们可以通过将它们链接到一个函数来处理这两种情况,该函数将设置我们的 PDF。
if (window.AdobeDC) displayPDF();
else {
document.addEventListener("adobe_dc_view_sdk.ready", () => displayPDF());
}
function displayPDF() {
console.log('Lets do some AWESOME PDF stuff!');
}
好了,我们如何显示 PDF 呢?为了接受所有默认设置,我们可以使用以下代码片段:
let adobeDCView = new AdobeDC.View({clientId: ADOBE_KEY, divId: "mypdf" });
adobeDCView.previewFile({
content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
metaData:{fileName: "cat.pdf"}
});
让我们来分析一下。首先,我们创建一个新的 AdobeDC.View
对象。clientId
值是之前获得的密钥。divId
是 DOM 中一个 <div>
的 ID,PDF 将在该 <div>
中渲染。我删除了之前添加的 HTML 注释,并在其中插入了一个带有该 ID 的空 <div>
。我还使用了一些 CSS 代码为其指定了宽度和高度:
#mypdf {
width: 100%;
height: 500px;
}
previewFile
方法接受两个主要参数。第一个是 PDF URL。PDF Embed API 同时支持 URL 和文件 Promise。对于 URL,我们希望确保已正确设置了 CORS。第二个值是关于 PDF 的元数据,在本例中是文件名。以下是结果:

以下是完整示例的 CodePen 代码,您可以克隆它、修改它并继续使用该密钥。
您会注意到 UI 包含您在任何 PDF 查看器中期望看到的相同工具,以及添加笔记和注释等功能。

注意上图中的“保存”图标。下载时,PDF 将包含注释和漂亮的标记绘制。
自定义体验
好的,您已经看到了基本示例,现在让我们来进行一些改进,并自定义体验。我们可能首先要做的就是更改嵌入模式,该模式控制 PDF 的显示方式。库支持四种不同的模式:
- 大小容器——默认模式,用于在
<div>
容器内渲染 PDF。它一次渲染一个页面。 - 全窗口——与大小容器类似,它会“填充”其父
<div>
,但会将整个 PDF 显示在一个可以滚动的“流”中。 - 内联——在网页中显示,类似于大小容器,但会将每个页面渲染成一个垂直堆叠。显然,不要对大型的 99 页 PDF 使用这种模式,除非您讨厌您的用户。(但是,如果您已经在用户访问您的网站时显示了“订阅我们的新闻稿”模态窗口,或者您的网站自动播放视频,那么您可以随意使用这种模式。)
- 灯箱——将 PDF 显示在一个居中的窗口中,同时将其他内容变暗。关闭显示的 UI 会自动包含在内。
要指定不同的视图,可以传递一个包含选项的第二个参数。例如:
function displayPDF() {
console.log('Lets do some AWESOME PDF stuff!');
let adobeDCView = new AdobeDC.View({clientId: ADOBE_KEY, divId: "mypdf" });
adobeDCView.previewFile({
content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
metaData:{fileName: "cat.pdf"}
},
{
embedMode: "IN_LINE"
});
}
请注意,在内联模式下,为您的 div 指定的高度将被忽略,以便 PDF 可以稍微伸展一下。您可以在这里查看该版本的演示:https://codepen.io/cfjedimaster/pen/OJpJRKr
让我们考虑另一个示例——使用灯箱和按钮,我们可以让用户在需要时加载 PDF。我们可以像这样修改 HTML 代码:
<html>
<head></head>
<body>
<h1>Cats are Everything</h1>
<p>
Cats are so incredibly awesome that I feel like
we should talk about them more. Here's a PDF
that talks about how awesome cats are.
</p>
<!-- PDF here! -->
<button id="showPDF" disabled>Show PDF</button>
<p>
Did you like that? Was it awesome? I think it was awesome!
</p>
</body>
</html>
我在 HTML 中添加了一个禁用的按钮,并删除了空的 <div>
。我们不需要它,因为灯箱模式将使用模态视图。现在我们修改 JavaScript 代码:
const ADOBE_KEY = 'b9151e8d6a0b4d798e0f8d7950efea91';
if(window.AdobeDC) enablePDF();
else {
document.addEventListener("adobe_dc_view_sdk.ready", () => enablePDF());
}
function enablePDF() {
let btn = document.querySelector('#showPDF');
btn.addEventListener('click', () => displayPDF());
btn.disabled = false;
}
function displayPDF() {
console.log('Lets do some AWESOME PDF stuff!');
let adobeDCView = new AdobeDC.View({clientId: ADOBE_KEY });
adobeDCView.previewFile({
content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
metaData:{fileName: "cat.pdf"}
},
{
embedMode: "LIGHT_BOX"
});
}
这里有两个主要变化。首先,检查库是否正在加载(或已加载)会运行 enablePDF
,该函数会从按钮中删除禁用的属性并添加一个点击事件。这将运行 displayPDF
。请注意,初始化程序不再使用 divId
。其次,请注意 embedMode
模式更改。您可以通过下面的 Pen 代码亲身体验。
您还有更多自定义选项,包括调整 UI 菜单和图标 以启用和禁用各种功能。
adobeDCView.previewFile({
content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
metaData:{fileName: "cat.pdf"}
},
{
showDownloadPDF: false,
showPrintPDF: false,
showAnnotationTools: false,
showLeftHandPanel: false
});
您可能猜到了这将做什么,但这里有一张带有默认选项的截图:

以下是禁用这些选项后的样子:

顺便说一句,为了明确起见,我们当然知道禁用下载按钮并不会“保护”这里看到的 PDF,因为 URL 仍然可以通过查看源代码看到。
同样,这只是一个简单的示例,因此请务必查看 自定义文档 以获取更多示例。
使用 API 并处理事件
除了自定义 UI,我们还可以对加载后的体验进行细粒度的控制。这是通过一个 API 支持的,该 API 可以返回有关 PDF 的信息,还可以监听事件。
使用 API 使用 previewFile
方法的结果。我们还没有使用它,但它会返回一个 Promise。API 的一个用途是获取元数据。以下是一个示例:
let resultPromise = adobeDCView.previewFile({
content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
metaData:{fileName: "cat.pdf"}
}, { embedMode:"SIZED_CONTAINER" });
resultPromise.then(adobeViewer => {
adobeViewer.getAPIs().then(apis => {
apis.getPDFMetadata()
.then(result => console.log(result))
.catch(error => console.log(error));
});
});
这将返回:
{
'numPages':6,
'pdfTitle':'Microsoft Word - Document1',
'fileName':''
}
除了 API 调用,我们还拥有深入的分析集成。虽然 文档 对此进行了详细说明(并讨论了与 Adobe Analytics 的集成),但您可以以任何对您有意义的方式处理 PDF 查看和交互事件。
例如,由于我们知道 PDF 中有多少页,并且可以监听查看页面的事件,因此我们可以注意到用户何时已查看所有页面。为了构建这个功能,我修改了 JavaScript 代码,如下所示:
const ADOBE_KEY = 'b9151e8d6a0b4d798e0f8d7950efea91';
//used to track what we've read
const pagesRead = new Set([1]);
let totalPages, adobeDCView, shownAlert=false;
if(window.AdobeDC) displayPDF();
else {
document.addEventListener("adobe_dc_view_sdk.ready", () => displayPDF());
}
function displayPDF() {
console.log('Lets do some AWESOME PDF stuff!');
adobeDCView = new AdobeDC.View({clientId: ADOBE_KEY, divId: "mypdf" });
let resultPromise = adobeDCView.previewFile({
content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
metaData:{fileName: "cat.pdf"}
}, { embedMode:"SIZED_CONTAINER" });
resultPromise.then(adobeViewer => {
adobeViewer.getAPIs().then(apis => {
apis.getPDFMetadata()
.then(result => {
totalPages = result.numPages;
console.log('totalPages', totalPages);
listenForReads();
})
.catch(error => console.log(error));
});
});
}
function listenForReads() {
const eventOptions = {
enablePDFAnalytics: true
}
adobeDCView.registerCallback(
AdobeDC.View.Enum.CallbackType.EVENT_LISTENER,
function(event) {
let page = event.data.pageNumber;
pagesRead.add(page);
console.log(`view page ${page}`);
if(pagesRead.size === totalPages && !shownAlert) {
alert('You read it all!');
shownAlert = true;
}
}, eventOptions
);
}
请注意,在我获取有关页数的信息后,我运行了一个函数,该函数开始监听页面查看事件。我使用一个 Set
来记录每个唯一的页面,当总数等于 PDF 中的页数时,我将发出一个 alert
消息。(当然,我们不知道读者是否真正阅读了文本。)虽然这有点无聊,但您可以在以下位置自己尝试一下:
const ADOBE_KEY = 'b9151e8d6a0b4d798e0f8d7950efea91';
//used to track what we've read
const pagesRead = new Set([1]);
let totalPages, adobeDCView, shownAlert=false;
if(window.AdobeDC) displayPDF();
else {
document.addEventListener("adobe_dc_view_sdk.ready", () => displayPDF());
}
function displayPDF() {
console.log('Lets do some AWESOME PDF stuff!');
adobeDCView = new AdobeDC.View({clientId: ADOBE_KEY, divId: "mypdf" });
let resultPromise = adobeDCView.previewFile({
content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
metaData:{fileName: "cat.pdf"}
}, { embedMode:"SIZED_CONTAINER" });
resultPromise.then(adobeViewer => {
adobeViewer.getAPIs().then(apis => {
apis.getPDFMetadata()
.then(result => {
totalPages = result.numPages;
console.log('totalPages', totalPages);
listenForReads();
})
.catch(error => console.log(error));
});
});
}
function listenForReads() {
const eventOptions = {
listenOn: [ AdobeDC.View.Enum.PDFAnalyticsEvents.PAGE_VIEW ],
enablePDFAnalytics: true
}
adobeDCView.registerCallback(
AdobeDC.View.Enum.CallbackType.EVENT_LISTENER,
function(event) {
/*
console.log("Type " + event.type);
console.log("Data " + JSON.stringify(event.data));
*/
let page = event.data.pageNumber;
pagesRead.add(page);
console.log(`view page ${page}`);
if(pagesRead.size === totalPages && !shownAlert) {
alert('You read it all!');
shownAlert = true;
}
}, eventOptions
);
}
如何了解更多
我希望本篇关于嵌入 API 的介绍对你有所帮助。以下是一些资源,可以帮助你更深入地了解它。
- 首先,你可以浏览一下 文档,它详细介绍了所有内容。
- 我们还有一个 实时演示,让你可以直观地看到所有功能,甚至可以为你生成代码。
- 如果你有任何问题或需要支持,我们有一个 论坛 供你提问,你也可以在 StackOverflow 上使用
adobe-embed-api
标签。 - 如果你需要在服务器级别处理 PDF,我们还有 Adobe PDF 工具 API 以及一个非常酷的 Adobe 文档生成 工具。这些工具不像 PDF 嵌入 API 那样免费,但你可以试用六个月,并通过 注册 试用。
最后,我们非常欢迎你对这方面的反馈。如果你有任何建议、想法、问题或其他任何事项,请随时联系我们!
您好。这个 API 可以使用内容直接 (base64) 还是只能使用 PDF URL?
它也可以使用文件 Promise,这让你可以编写代码,允许用户从系统中选择 PDF 或拖放 PDF。
它没有那么多花里胡哨的功能,但我更喜欢 Mozilla 的 PDF.js (https://mozilla.github.io/pdf.js/)
如何设置代码的单个实例,并动态传递要显示的 PDF 的 URL,以便在一个页面上可以有多个 PDF?
你可以在查询字符串中传递 PDF 的 URL 路径,然后在代码中解析它。我手头没有演示,但如果你需要,我可以快速创建一个。
我喜欢这种嵌入 PDF 的方式。有人知道我们如何保护 PDF,防止通过查看源代码进行下载吗?
你可以禁用保存和打印,但如果你在互联网上托管资源,几乎不可能完全隐藏它。你可以要求用户登录你的网站,并只将 PDF 数据流式传输到已登录的客户端(文件 Promise 与嵌入 API 兼容),但这只能将它锁定到你已知的用户。
提醒一下,“全屏”,而不是“大小容器”,是默认设置。抱歉!
我绞尽脑汁,对于嵌入的 PDF,我无法让
focusOnRendering: false
正常工作。PDF 在视窗之外(在页面的更下方),但只要它加载,页面就会聚焦在 PDF 上
您好,adam,我无法重现此问题。我创建了一个 CodePen,里面包含一个文本字段和一个用于 PDF 的 div。PDF 不会在 5 秒内加载。我在字段中输入内容,并等待……当 PDF 加载时,它并没有获得焦点。
如果你想直接联系我,我的邮箱是 [email protected].