之前手里好几个项目都需要用到pdf预览,在网上收罗了一大堆资料,最终选定了pdf.js。
原因:
不用pdf.js的话,就需要去安装各种环境的pdf插件,比如vue环境的vue-pdf,虽然可以自定义部分功能,但是除了它的展示,其他功能需要自己去添加(略麻烦),最不能忍的是不兼容ie!!!(看其他文章有适配ie的,不知道是不是博主环境版本原因,实在是显示不了),对于angular环境,也没找到适用的插件。
pdf.js虽然只能兼容到ie10+,但现在都什么时代了,使用低版本浏览器的用户毕竟占少数。而且它好歹是原生的,可以适用任何框架(jquery、vue及angular等),只要配置好一份插件,就可吃遍天下的既视感。
1.下载
参照链接:
博主用的链接文章中提到的第一种方法(使用自带的viewer.html预览)
插件存放路径:原生框架可以放置任何位置,文中就放置于common/pdf路径,vue与angular框架就需要放置于静态资源文件static/pdf路径
2.更改配置文件
参照链接:
(1)修改view.js(找到以下内容加以更改)
// var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf'; '' //注释默认
...
//注释对于是否允许跨域的判断
// var viewerOrigin = new URL(window.location.href).origin || 'null';
// if (HOSTED_VIEWER_ORIGINS.indexOf(viewerOrigin) >= 0) {
// return;
// }
// var fileOrigin = new URL(file, window.location.href).origin;
// if (fileOrigin !== viewerOrigin) {
// throw new Error('file origin does not match viewer\'s');
// }
//当直接打开base64时,file是个对象,而不是string类型的url,所以此处需要判断
if (file && typeof file =='string') {
var fileOrigin = new URL(file, window.location.href).origin;
}
...
webViewerOpenFileViaURL = function webViewerOpenFileViaURL(file) {
//增加判断file是string
if (file && typeof file=='string' && file.lastIndexOf('file:', 0) === 0) {
PDFViewerApplication.setTitleUsingUrl(file);
var xhr = new XMLHttpRequest();
xhr.onload = function () {
PDFViewerApplication.open(new Uint8Array(xhr.response));
};
try {
xhr.open('GET', file);
xhr.responseType = 'arraybuffer';
xhr.send();
} catch (ex) {
PDFViewerApplication.l10n.get('loading_error', null, 'An error occurred while loading the PDF.').then(function (msg) {
PDFViewerApplication.error(msg, ex);
});
}
return;
}
if (file) {
PDFViewerApplication.open(file);
}
};
(2)修改view.html(下段代码需放置于view.js文件引用之前)
上述链接的文中是用sessionStorage来存储base64,会有一个弊端,如果base64太长,数据过大,会超出sessionStorage的存储上限,这时候就会去想有没有办法扩大sessionStorage的存储容量,博主找了一些方法,经测试之后都不能有效解决这个问题。最终选择了一个稳妥的方式:用iframe嵌套(将数据存储于iframe层某个dom元素里,获取数据时直接在view.html层读取父级dom元素的数据即可,就不用大费周章的去想怎么存储数据的问题),在引用的时候会把具体代码呈现。
<script type="text/javascript">
var DEFAULT_URL = "";
var pdfUrl = document.location.search.substring(1);
if (null == pdfUrl || "" == pdfUrl) {
var BASE64_MARKER = ';base64,'; //声明文件流编码格式
var preFileId = "";
var pdfAsDataUri = window.top.document.getElementById('baseUrl').innerHTML; //获取父级dom存储的数据
var pdfAsArray = convertDataURIToBinary(pdfAsDataUri);
DEFAULT_URL = pdfAsArray;
//编码转换
function convertDataURIToBinary(dataURI) {
//[RFC2045]中有规定:Base64一行不能超过76字符,超过则添加回车换行符。因此需要把base64字段中的换行符,回车符给去掉。
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var newUrl = dataURI.substring(base64Index).replace(/[\n\r]/g, '');
var raw = window.atob(newUrl); //这个方法在ie内核下无法正常解析。
var rawLength = raw.length;
//转换成pdf.js能直接解析的Uint8Array类型
var array = new Uint8Array(new ArrayBuffer(rawLength));
for (i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i) & 0xff;
}
return array;
}
}
</script>
3.引用(打开一个新窗口,以iframe的形式嵌套view.html)
文中数据来源是接口获取,它可能是base64格式,也可能是文件流,博主下文都会给出具体示例。(接口需要的参数传至下文提到的新页面,接口也在该处调用,怎么打开新页面并传参就不用博主多讲了。。)
(1)原生框架
新建pdf_view.html
html部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<title></title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<style>
html,body, #content{height:100%;}
body{margin:0;overflow:hidden;}
#content{
text-align:center;
background:rgba(0,0,0,.6);
}
img{
max-width:100%;
max-height:100%;
}
</style>
</head>
<body>
<div id="baseUrl" hidden></div> <!--存储base64数据-->
<div id="content"></div> <!--动态渲染iframe-->
</body>
</html>
script部分:
var common = require("common");
var url = common.Url.resumeApiHost;
var fileId = common.getQueryString('fileId');
var fileName = common.getQueryString('fileName');
document.title = fileName;
//获取文件流
function getFileBlob() {
var header = {};
header['Authorization'] = 'cmbnthr ' + common.Cookies.getCookie("userToken");
new common.ajaxRequest({
url: url + "cmbntResume/attachment/view/"+fileId,
type: "GET",
param: '',
header: header,
callBack: function (data) {if(IEVersion()<10 && IEVersion()!=-1){
common.Common.jAlert("请更新您的浏览器!");
return;
}
$('#baseUrl').html('data:application/pdf;base64,'+data.data)
$('#content').html('<iframe id="iframe" src="../../pdf/web/viewer.html" frameborder="0" width="100%" height="100%" border="0"></iframe>')
}
})
}
getFileBlob();
//IE版本判断
function IEVersion() {
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器
var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
if (isIE) {
var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
reIE.test(userAgent);
var fIEVersion = parseFloat(RegExp["$1"]);
if (fIEVersion == 7) {
return 7;
} else if (fIEVersion == 8) {
return 8;
} else if (fIEVersion == 9) {
return 9;
} else if (fIEVersion == 10) {
return 10;
} else {
return 6;//IE版本<=7
}
} else if (isEdge) {
return 'edge';//edge
} else if (isIE11) {
return 11; //IE11
} else {
return -1;//不是ie浏览器
}
}
(2)vue框架
新建pdfView.vue
<template>
<div>
<div id="baseUrl" hidden>{{pdfData}}</div>
<iframe id="iframes" v-if="pdfData" :src="pdfUrl" frameborder="0" width="100%" height="100%"></iframe>
</div>
</template>
<script>
import { downloadFileBlob } from '@/api/checkAppointment/request'
export default {
data(){
return{
pdfUrl: '',
pdfData: ''
}
},
created(){
downloadFileBlob({fileIDName: window.location.hash.split('=')[1] || ''}).then(res => {
//这里返回的是文件流,把它转换成base64格式
const blob = new Blob([res])
const _this = this
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
_this.pdfData = reader.result;
_this.pdfUrl="/static/pdf/web/viewer.html"
}
})
},
methods:{
}
}
</script>
<style lang="scss" scoped>
iframe{
height:calc(100vh - 20px)
}
</style>
其他框架同理,如有问题,欢迎评论!