在 Vue 项目中首先通过 npm 安装 PDFObject 插件。
npm install pdfobject
然后通过 import PDFObject from 'pdfobject'; 将 PDFObject 导入到页面。下面是一个使用例子。
<template>
<div>
<div ref="myContainer"></div>
</div>
</template>
<script>
import PDFObject from 'pdfobject';
export default {
mounted() {
this.embedPDF();
},
methods: {
embedPDF() {
const options = {
width: "100%",
height: "500px"
};
PDFObject.embed("myfile.pdf", this.$refs.myContainer, options);
//PDFObject.embed("https://pdfobject.com/pdf/sample-3pp.pdf", "#myContainer",
{ title: "PDF version of your banking statement" });
}
}
}
</script>
不安装包也可以直接引用 PDFObject 的源码PDFObject/pdfobject.js at master · pipwerks/PDFObject · GitHub
引用import PDFObject from './index';
后通过PDFObject
.embed 调用
/**
* PDFObject v2.3.0
* https://github.com/pipwerks/PDFObject
* @license
* Copyright (c) 2008-2024 Philip Hutchison
* @modifiedBy KonghaYao 更改为 ESM 导出
* MIT-style license: http://pipwerks.mit-license.org/
* UMD module pattern from https://github.com/umdjs/umd/blob/master/templates/returnExports.js
*/
'use strict';
//PDFObject is designed for client-side (browsers), not server-side (node)
//Will choke on undefined navigator and window vars when run on server
//Return boolean false and exit function when running server-side
export let support = true;
if (typeof window === 'undefined' || window.navigator === undefined || window.navigator.userAgent === undefined) {
support = false;
}
const pdfobjectversion = '2.3.0';
const win = window;
const nav = win.navigator;
const ua = nav.userAgent;
let suppressConsole = false;
//Fallback validation when navigator.pdfViewerEnabled is not supported
const isModernBrowser = function () {
/*
userAgent sniffing is not the ideal path, but most browsers revoked the ability to check navigator.mimeTypes
for security purposes. As of 2023, browsers have begun implementing navigator.pdfViewerEnabled, but older versions
do not have navigator.pdfViewerEnabled or the ability to check navigator.mimeTypes. We're left with basic browser
sniffing and assumptions of PDF support based on browser vendor.
*/
//Chromium has provided native PDF support since 2011.
//Most modern browsers use Chromium under the hood: Google Chrome, Microsoft Edge, Opera, Brave, Vivaldi, Arc, and more.
//Chromium uses the PDFium rendering engine, which is based on Foxit's PDF rendering engine.
//Note that MS Edge opts to use a different PDF rendering engine. As of 2024, Edge uses a version of Adobe's Reader
const isChromium = win.chrome !== undefined;
//Safari on macOS has provided native PDF support since 2009.
//This code snippet also detects the DuckDuckGo browser, which uses Safari/Webkit under the hood.
const isSafari =
win.safari !== undefined || (nav.vendor !== undefined && /Apple/.test(nav.vendor) && /Safari/.test(ua));
//Firefox has provided PDF support via PDFJS since 2013.
const isFirefox = win.Mozilla !== undefined || /irefox/.test(ua);
return isChromium || isSafari || isFirefox;
};
/*
Special handling for Internet Explorer 11.
Check for ActiveX support, then whether "AcroPDF.PDF" or "PDF.PdfCtrl" are valid.
IE11 uses ActiveX for Adobe Reader and other PDF plugins, but window.ActiveXObject will evaluate to false.
("ActiveXObject" in window) evaluates to true.
MS Edge does not support ActiveX so this test will evaluate false for MS Edge.
*/
const validateAX = function (type) {
let ax = null;
try {
ax = new ActiveXObject(type);
} catch (e) {
//ensure ax remains null when ActiveXObject attempt fails
ax = null;
}
return !!ax; //convert resulting object to boolean
};
const hasActiveXPDFPlugin = function () {
return 'ActiveXObject' in win && (validateAX('AcroPDF.PDF') || validateAX('PDF.PdfCtrl'));
};
const checkSupport = function () {
//Safari on iPadOS doesn't report as 'mobile' when requesting desktop site, yet still fails to embed PDFs
const isSafariIOSDesktopMode =
nav.platform !== undefined &&
nav.platform === 'MacIntel' &&
nav.maxTouchPoints !== undefined &&
nav.maxTouchPoints > 1;
const isMobileDevice = isSafariIOSDesktopMode || /Mobi|Tablet|Android|iPad|iPhone/.test(ua);
//As of June 2023, no mobile browsers properly support inline PDFs. If mobile, just say no.
if (isMobileDevice) {
return false;
}
//Modern browsers began supporting navigator.pdfViewerEnabled in late 2022 and early 2023.
const supportsPDFVE = typeof nav.pdfViewerEnabled === 'boolean';
//If browser supports nav.pdfViewerEnabled and is explicitly saying PDFs are NOT supported (e.g. PDFJS disabled by user in Firefox), respect it.
if (supportsPDFVE && !nav.pdfViewerEnabled) {
return false;
}
return (supportsPDFVE && nav.pdfViewerEnabled) || isModernBrowser() || hasActiveXPDFPlugin();
};
//Determines whether PDF support is available
const supportsPDFs = checkSupport();
//Create a fragment identifier for using PDF Open parameters when embedding PDF
const buildURLFragmentString = function (pdfParams) {
let string = '';
let prop;
const paramArray = [];
let fdf = '';
//The comment, viewrect, and highlight parameters require page to be set first.
//Check to ensure page is used if comment, viewrect, or highlight are specified
if (pdfParams.comment || pdfParams.viewrect || pdfParams.highlight) {
if (!pdfParams.page) {
//If page is not set, use the first page
pdfParams.page = 1;
//Inform user that page needs to be set properly
embedError(
'The comment, viewrect, and highlight parameters require a page parameter, but none was specified. Defaulting to page 1.',
);
}
}
//Let's go ahead and ensure page is always the first parameter.
if (pdfParams.page) {
paramArray.push('page=' + encodeURIComponent(pdfParams.page));
delete pdfParams.page;
}
//FDF needs to be the last parameter in the string
if (pdfParams.fdf) {
fdf = pdfParams.fdf;
delete pdfParams.fdf;
}
//Add all other parameters, as needed
if (pdfParams) {
for (prop in pdfParams) {
if (pdfParams.hasOwnProperty(prop)) {
paramArray.push(encodeURIComponent(prop) + '=' + encodeURIComponent(pdfParams[prop]));
}
}
//Add fdf as the last parameter, if needed
if (fdf) {
paramArray.push('fdf=' + encodeURIComponent(fdf));
}
//Join all parameters in the array into a string
string = paramArray.join('&');
//The string will be empty if no PDF Parameters were provided
//Only prepend the hash if the string is not empty
if (string) {
string = '#' + string;
}
}
return string;
};
const embedError = function (msg) {
if (!suppressConsole) {
console.log('[PDFObject]', msg);
}
return false;
};
const emptyNodeContents = function (node) {
while (node.firstChild) {
node.removeChild(node.firstChild);
}
};
const getTargetElement = function (targetSelector) {
//Default to body for full-browser PDF
let targetNode = document.body;
//If a targetSelector is specified, check to see whether
//it's passing a selector, jQuery object, or an HTML element
if (typeof targetSelector === 'string') {
//Is CSS selector
targetNode = document.querySelector(targetSelector);
} else if (win.jQuery !== undefined && targetSelector instanceof jQuery && targetSelector.length) {
//Is jQuery element. Extract HTML node
targetNode = targetSelector.get(0);
} else if (targetSelector.nodeType !== undefined && targetSelector.nodeType === 1) {
//Is HTML element
targetNode = targetSelector;
}
return targetNode;
};
const convertBase64ToDownloadableLink = function (b64, filename, targetNode, fallbackHTML) {
//IE-11 safe version. More verbose than modern fetch()
if (window.Blob && window.URL && window.URL.createObjectURL) {
const xhr = new XMLHttpRequest();
xhr.open('GET', b64, true);
xhr.responseType = 'blob';
xhr.onload = function () {
if (xhr.status === 200) {
const blob = xhr.response;
const link = document.createElement('a');
link.innerText = 'Download PDF';
link.href = URL.createObjectURL(blob);
link.setAttribute('download', filename);
targetNode.innerHTML = fallbackHTML.replace(/\[pdflink\]/g, link.outerHTML);
}
};
xhr.send();
}
};
const generatePDFObjectMarkup = function (
embedType,
targetNode,
url,
pdfOpenFragment,
width,
height,
id,
title,
omitInlineStyles,
customAttribute,
PDFJS_URL,
) {
//Ensure target element is empty first
emptyNodeContents(targetNode);
let source = url;
if (embedType === 'pdfjs') {
//If PDFJS_URL already contains a ?, assume querystring is in place, and use an ampersand to append PDFJS's file parameter
const connector = PDFJS_URL.indexOf('?') !== -1 ? '&' : '?';
source = PDFJS_URL + connector + 'file=' + encodeURIComponent(url) + pdfOpenFragment;
} else {
source += pdfOpenFragment;
}
const el = document.createElement('iframe');
el.className = 'pdfobject';
el.type = 'application/pdf';
el.title = title;
el.src = source;
el.allow = 'fullscreen';
el.frameborder = '0';
if (id) {
el.id = id;
}
if (!omitInlineStyles) {
let style = 'border: none;';
if (targetNode !== document.body) {
//assign width and height to target node
style += 'width: ' + width + '; height: ' + height + ';';
} else {
//this is a full-page embed, use CSS to fill the viewport
style += 'position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%;';
}
el.style.cssText = style;
}
//Allow developer to insert custom attribute on iframe element, but ensure it does not conflict with attributes used by PDFObject
const reservedTokens = ['className', 'type', 'title', 'src', 'style', 'id', 'allow', 'frameborder'];
if (customAttribute && customAttribute.key && reservedTokens.indexOf(customAttribute.key) === -1) {
el.setAttribute(customAttribute.key, typeof customAttribute.value !== 'undefined' ? customAttribute.value : '');
}
targetNode.classList.add('pdfobject-container');
targetNode.appendChild(el);
return targetNode.getElementsByTagName('iframe')[0];
};
const embed = function (url, targetSelector, options) {
//If targetSelector is not defined, convert to boolean
const selector = targetSelector || false;
//Ensure options object is not undefined -- enables easier error checking below
const opt = options || {};
//Get passed options, or set reasonable defaults
suppressConsole = typeof opt.suppressConsole === 'boolean' ? opt.suppressConsole : false;
const id = typeof opt.id === 'string' ? opt.id : '';
const page = opt.page || false;
const pdfOpenParams = opt.pdfOpenParams || {};
const fallbackLink =
typeof opt.fallbackLink === 'string' || typeof opt.fallbackLink === 'boolean' ? opt.fallbackLink : true;
const width = opt.width || '100%';
const height = opt.height || '100%';
const title = opt.title || 'Embedded PDF';
const forcePDFJS = typeof opt.forcePDFJS === 'boolean' ? opt.forcePDFJS : false;
const omitInlineStyles = typeof opt.omitInlineStyles === 'boolean' ? opt.omitInlineStyles : false;
const PDFJS_URL = opt.PDFJS_URL || false;
const targetNode = getTargetElement(selector);
let pdfOpenFragment = '';
const customAttribute = opt.customAttribute || {};
const fallbackHTML_default =
'<p>This browser does not support inline PDFs. Please download the PDF to view it: [pdflink]</p>';
//Ensure URL is available. If not, exit now.
if (typeof url !== 'string') {
return embedError('URL is not valid');
}
//If target element is specified but is not valid, exit without doing anything
if (!targetNode) {
return embedError('Target element cannot be determined');
}
//page option overrides pdfOpenParams, if found
if (page) {
pdfOpenParams.page = page;
}
//Stringify optional Adobe params for opening document (as fragment identifier)
pdfOpenFragment = buildURLFragmentString(pdfOpenParams);
// --== Do the dance: Embed attempt #1 ==--
//If the forcePDFJS option is invoked, skip everything else and embed as directed
if (forcePDFJS && PDFJS_URL) {
return generatePDFObjectMarkup(
'pdfjs',
targetNode,
url,
pdfOpenFragment,
width,
height,
id,
title,
omitInlineStyles,
customAttribute,
PDFJS_URL,
);
}
// --== Embed attempt #2 ==--
//Embed PDF if support is detected, or if this is a relatively modern browser
if (supportsPDFs) {
return generatePDFObjectMarkup(
'iframe',
targetNode,
url,
pdfOpenFragment,
width,
height,
id,
title,
omitInlineStyles,
customAttribute,
);
}
// --== Embed attempt #3 ==--
//If everything else has failed and a PDFJS fallback is provided, try to use it
if (PDFJS_URL) {
return generatePDFObjectMarkup(
'pdfjs',
targetNode,
url,
pdfOpenFragment,
width,
height,
id,
title,
omitInlineStyles,
customAttribute,
PDFJS_URL,
);
}
// --== PDF embed not supported! Use fallback ==--
//Display the fallback link if available
if (fallbackLink) {
//If a custom fallback has been provided, handle it now
if (typeof fallbackLink === 'string') {
//Ensure [url] is set in custom fallback
targetNode.innerHTML = fallbackLink.replace(/\[url\]/g, url);
} else {
//If the PDF is a base64 string, convert it to a downloadable link
if (url.indexOf('data:application/pdf;base64') !== -1) {
//Asynchronously append the link to the targetNode
convertBase64ToDownloadableLink(url, 'file.pdf', targetNode, fallbackHTML_default);
} else {
//Use default fallback link
const link = "<a href='" + url + "'>Download PDF</a>";
targetNode.innerHTML = fallbackHTML_default.replace(/\[pdflink\]/g, link);
}
}
}
return embedError('This browser does not support embedded PDFs');
};
export default {
embed: function (a, b, c) {
return embed(a, b, c);
},
pdfobjectversion: (function () {
return pdfobjectversion;
})(),
supportsPDFs: (function () {
return supportsPDFs;
})(),
};