vue项目实现常见的三种文件类型在线预览(pdf/word文件excel表格)

2022年6月9日09:46:44

之前做PDF预览一直用的pdf.js,这次没有太多附加需求比较简单简,所以决定用vue-pdf这个组件,虽然说它没有原生那样强大,但已经满足常用的需求了,重要是这个组件使用简单。顺便也把word文件和excel表格预览也整理了下,接下来我们直接进入正题!
一、预览word文件
1.安装 npm 依赖

npm i docx-preview@0.1.4
npm i jszip

2.预览在线地址文件

<template><divclass="home"><div ref="file"></div></div></template><script>import axiosfrom'axios'const docx=require('docx-preview');
window.JSZip=require('jszip')exportdefault{mounted(){axios({
      method:'get',
      responseType:'blob',// 设置响应文件格式
      url:'/docx',}).then(({data})=>{
      docx.renderAsync(data,this.$refs.file)// 渲染到页面预览})}}</script>

3.预览本地文件

<template><divclass="my-component" ref="preview"><input type="file" @change="preview" ref="file"></div></template><script>const docx=require('docx-preview');
window.JSZip=require('jszip')exportdefault{
  methods:{preview(e){
      docx.renderAsync(this.$refs.file.files[0],this.$refs.preview)// 渲染到页面预览}}};</script><style lang="less" scoped>.my-component{
  width:100%;
  height:90vh;
  border:1px solid #000;}</style>

二、预览excel表格
1.安装依赖

npm i xlsx

2.预览在线表格

<template><divclass="home"><div v-html="tableau"></div></div></template><script>import axiosfrom'axios'importXLSXfrom"xlsx";exportdefault{data(){return{
      tableau:null,}},mounted(){
     axios.get('/xlsx',{
       responseType:"arraybuffer",// 设置响应体类型为arraybuffer}).then(({data})=>{let workbook=XLSX.read(newUint8Array(data),{type:"array"});// 解析数据var worksheet= workbook.Sheets[workbook.SheetNames[0]];// workbook.SheetNames 下存的是该文件每个工作表名字,这里取出第一个工作表this.tableau=XLSX.utils.sheet_to_html(worksheet);// 渲染})}}</script>

三、pdf预览
1.安装依赖vue-pdf

npm install--save vue-pdf

2.在需要的页面注册

<script>importPDFfrom'vue-pdf'exportdefault{
  components:{PDF,},data(){return{}}</script>

3.使用,一般预览pdf时都是很多页的,为了提升性能可以做个分页。page: 当前显示的页数,比如第一页page=1;rotate : 旋转角度,比如0就是不旋转,+90,-90 就是水平旋转。progress :当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了。page-loaded :页面加载成功的回调函数,不咋能用到。num-pages :总页数;error :加载错误的回调link-clicked:单机pdf内的链接会触发。print 这个是打印函数。(注意:谷歌浏览器预览时会出现乱码,这个问题是因为你pdf中使用了自定义字体导致的。若要解决须替换node_modules/vue-pdf/src/pdfjsWrapper.js,替换的pdfjsWrapper.js我放在文章最后)

<!-- 预览PDF--><el-dialog v-dialogDrag:visible.sync="previewDialog"><template><div><divclass="tools"><el-button:theme="'default'" type="submit":title="'上一页'" @click.stop="prePage"class="mr10"> 上一页</el-button><el-button:theme="'default'" type="submit":title="'下一页'" @click.stop="nextPage"class="mr10"> 下一页</el-button><divclass="page">{{pageNum}}/{{pageTotalNum}}</div><el-button:theme="'default'" type="submit":title="'顺时针旋转'" @click.stop="clock"class="mr10"> 顺时针旋转</el-button><el-button:theme="'default'" type="submit":title="'逆时针旋转'" @click.stop="counterClock"class="mr10"> 逆时针旋转</el-button><el-button:theme="'default'" type="submit":title="'打印'" @click.stop="pdfPrintAll"class="mr10"> 打印</el-button></div><pdf ref="pdf":src="url":page="pageNum":rotate="pageRotate" @progress="loadedRatio = $event" @page-loaded="pageLoaded($event)" 
            @num-pages="pageTotalNum=$event" @error="pdfError($event)"  @link-clicked="page = $event"></pdf></div></template></el-dialog><script>importPDFfrom'vue-pdf'exportdefault{
  components:{PDF,},data(){return{
      	previewDialog:false,
      	url:"http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf",
      	pageNum:1,
      	pageTotalNum:1,
      	pageRotate:0,// 加载进度
      	loadedRatio:0,
      	curPageNum:0,},
      methods:{/**
     * 预览PDF
     */previewPDF(row,index){this.previewDialog=true;
      console.log("", row,index);},// 上一页函数,prePage(){var page=this.pageNum
      page= page>1? page-1:this.pageTotalNumthis.pageNum= page},// 下一页函数nextPage(){var page=this.pageNum
      page= page<this.pageTotalNum? page+1:1this.pageNum= page},// 页面顺时针翻转90度。clock(){this.pageRotate+=90},// 页面逆时针翻转90度。counterClock(){this.pageRotate-=90},// 页面加载回调函数,其中e为当前页数pageLoaded(e){this.curPageNum= e},// 错误时回调函数。pdfError(error){
      console.error(error)},// 打印全部pdfPrintAll(){/**
       * 打印界面字符乱码是因为你pdf中使用了自定义字体导致的,谷歌浏览器打印的时候预览界面真的变成了真·方块字 ,解决方案如下:
       * 用文章最后的pdfjsWrapper.js在替换掉node_modules/vue-pdf/src/pdfjsWrapper.js
       */
      console.log("打印");this.$refs.pdf.print()},},}</script>

4.加载本地pdf文件
如果需要加载本地pdf文件(不需要则不用配置),需要我们做一下本地配置flie-loader才行,否则webpack无法编译pdf类型的文件,配置方法也很简单,在项目根目录找到vue.config.js文件(若没有则在根目录下新建一个vue.config.js)。之后再url:require("…/assets/xxx.pdf")就没有任何问题了,注意,vue-pdf src接收的是string对象,如果直接传url这里报错了,需要传url.default一下。
先安装file-loader

npm install--save file-loader

然后在vue.config.js中加入以下内容:

module.exports={chainWebpack:config=>{const fileRule= config.module.rule('file')
        fileRule.uses.clear()
        fileRule.test(/\.pdf|ico$/).use('file-loader').loader('file-loader').options({
                limit:10000,})},
    publicPath:'./'}

5.解决pdf使用自定义字体预览和打印乱码问题:pdfjsWrapper.js

import{ PDFLinkService}from'pdfjs-dist/es5/web/pdf_viewer';var pendingOperation= Promise.resolve();exportdefaultfunction(PDFJS){functionisPDFDocumentLoadingTask(obj){returntypeof(obj)==='object'&& obj!==null&& obj.__PDFDocumentLoadingTask===true;// or: return obj.constructor.name === 'PDFDocumentLoadingTask';}functioncreateLoadingTask(src, options){var source;if(typeof(src)==='string')
			source={ url: src};elseif( srcinstanceofUint8Array)
			source={ data: src};elseif(typeof(src)==='object'&& src!==null)
			source= Object.assign({}, src);elsethrownewTypeError('invalid src type');// source.verbosity = PDFJS.VerbosityLevel.INFOS;// source.pdfBug = true;// source.stopAtErrors = true;if( options&& options.withCredentials)
			source.withCredentials= options.withCredentials;var loadingTask=PDFJS.getDocument(source);
		loadingTask.__PDFDocumentLoadingTask=true;// since PDFDocumentLoadingTask is not publicif( options&& options.onPassword)
			loadingTask.onPassword= options.onPassword;if( options&& options.onProgress)
			loadingTask.onProgress= options.onProgress;return loadingTask;}functionPDFJSWrapper(canvasElt, annotationLayerElt, emitEvent){var pdfDoc=null;var pdfPage=null;var pdfRender=null;var canceling=false;

		canvasElt.getContext('2d').save();functionclearCanvas(){

			canvasElt.getContext('2d').clearRect(0,0, canvasElt.width, canvasElt.height);}functionclearAnnotations(){while( annotationLayerElt.firstChild)
				annotationLayerElt.removeChild(annotationLayerElt.firstChild);}this.destroy=function(){if( pdfDoc===null)return;// Aborts all network requests and destroys worker.
			pendingOperation= pdfDoc.destroy();
			pdfDoc=null;}this.getResolutionScale=function(){return canvasElt.offsetWidth/ canvasElt.width;}this.printPage=function(dpi, pageNumberOnly){if( pdfPage===null)return;// 1in == 72pt// 1in == 96pxvarPRINT_RESOLUTION= dpi===undefined?150: dpi;varPRINT_UNITS=PRINT_RESOLUTION/72.0;varCSS_UNITS=96.0/72.0;var printContainerElement= document.createElement('div');
			printContainerElement.setAttribute('id','print-container')functionremovePrintContainer(){
				printContainerElement.parentNode.removeChild(printContainerElement);}newPromise(function(resolve, reject){
				printContainerElement.frameBorder='0';
				printContainerElement.scrolling='no';
				printContainerElement.width='0px;'
				printContainerElement.height='0px;'
				printContainerElement.style.cssText='position: absolute; top: 0; left: 0';

				window.document.body.appendChild(printContainerElement);resolve(window)}).then(function(win){

				win.document.title='';return pdfDoc.getPage(1).then(function(page){var viewport= page.getViewport({ scale:1});
					printContainerElement.appendChild(win.document.createElement('style')).textContent='@supports ((size:A4) and (size:1pt 1pt)) {'+'@page { margin: 1pt; size: '+((viewport.width*PRINT_UNITS)/CSS_UNITS)+'pt '+((viewport.height*PRINT_UNITS)/CSS_UNITS)+'pt; }'+'}'+'#print-canvas { display: none }'+'@media print {'+'body { margin: 0 }'+'#print-canvas { page-break-before: avoid; page-break-after: always; page-break-inside: avoid; display: block }'+'body > *:not(#print-container) { display: none; }'+'}'+'@media screen {'+'body { margin: 0 }'+'}'return win;})}).then(function(win){var allPages=[];for(var pageNumber=1; pageNumber<= pdfDoc.numPages;++pageNumber){if( pageNumberOnly!==undefined&& pageNumberOnly.indexOf(pageNumber)===-1)continue;

					allPages.push(
						pdfDoc.getPage(pageNumber).then(function(page){var viewport= page.getViewport({ scale:1});var printCanvasElt= printContainerElement.appendChild(win.document.createElement('canvas'));
							printCanvasElt.setAttribute('id','print-canvas')
							printCanvasElt.width=(viewport.width*PRINT_UNITS);
							printCanvasElt.height=(viewport.height*PRINT_UNITS);return page.render({
								canvasContext: printCanvasElt.getContext('2d'),
								transform:[// Additional transform, applied just before viewport transform.PRINT_UNITS,0,0,PRINT_UNITS,0,0],
								viewport: viewport,
								intent:'print'}).promise;}));}

				Promise.all(allPages).then(function(){

					win.focus();// Required for IEif(win.document.queryCommandSupported(
  • 作者:无月大大
  • 原文链接:https://blog.csdn.net/weixin_52103939/article/details/122447620
    更新时间:2022年6月9日09:46:44 ,共 8162 字。