本篇内容主要讲解“vue项目怎么用后端返回的文件流实现docx和pdf文件预览”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue项目怎么用后端返回的文件流实现docx和pdf文件预览”吧!
实现效果图
大家先看一下实现的效果,分别是docx文件预览和pdf文件预览;
原型是从一个table列表的操作中点击查看源文件,跳转到预览页面:
docx文件预览
pdf文件预览(可实现翻页功能)
docx-preview文件预览
首先安装docx-preview
npm install docx-preview
点击【查看源文件】
... <el-button type="text" @click="clickView(scope.row)">查看源文件</el-button> ...
在点击事件方法中,首先进行if判断文件类型,不同的文件类型走不同的逻辑,这里判断是否为.docx文件,然后进行路由跳转到文件预览页面,把id带过去;
... //查看源文件 clickView(row){ if((row.fileName).indexOf('.docx') !== -1){ this.$router.push({ path: "/dataStandar/knowledgeBase/createBase/vuedocx", query: { //要传的参数 id: row.id, }, }); }else{ //这里代码是pdf文件预览,此处先省略 ... } }, ...
vueDocx.vue组件
<template> <div ref="file" class="files" ></div> </template> <script> import { getSourceFileById, //接口函数返回的文件流 } from '@/api/dataStandar/knowledgeBase/createBase' import {renderAsync } from "docx-preview"; //引入renderAsync 方法 export default { data(){ return { docxOptions: { className: "kaimo-docx-666", // string:默认和文档样式类的类名/前缀 inWrapper: true, // boolean:启用围绕文档内容的包装器渲染 ignoreWidth: false, // boolean:禁用页面的渲染宽度 ignoreHeight: false, // boolean:禁止渲染页面高度 ignoreFonts: false, // boolean:禁用字体渲染 breakPages: true, // boolean:在分页符上启用分页 ignoreLastRenderedPageBreak: true, // boolean:在 lastRenderedPageBreak 元素上禁用分页 experimental: false, // boolean:启用实验功能(制表符停止计算) trimXmlDeclaration: true, // boolean:如果为true,解析前会从 xmlTemplate 文档中移除 xmlTemplate 声明 useBase64URL: false, // boolean:如果为true,图片、字体等会转为base 64 URL,否则使用URL.createObjectURL useMathMLPolyfill: false, // boolean:包括用于 chrome、edge 等的 MathML polyfill。 showChanges: false, // boolean:启用文档更改的实验性渲染(插入/删除) debug: false, // boolean:启用额外的日志记录 }, } }, mounted(){ this.initView() }, methods:{ initView(){ var id = this.$route.query.id this.loading = this.$loading({ lock: true, text: "正在加载...", spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.6)' }); getSourceFileById({},id).then(res => { let bodyContainer = this.$refs.file var data = res.data if(res.status == 200){ renderAsync( data, // Blob | ArrayBuffer | Uint8Array, 可以是 JSZip.loadAsync 支持的任何类型 bodyContainer, // HTMLElement 渲染文档内容的元素, null, // HTMLElement, 用于呈现文档样式、数字、字体的元素。如果为 null,则将使用 bodyContainer。 this.docxOptions // 配置 ) setTimeout(() => { this.loading.close() },1000) } }) }, } } </script> <style> .files{ padding: 0 20px; } </style>
以上就是docx文件预览逻辑和代码,使用比较简单;
pdf文件预览
首先安装vue-pdf
npm install vue-pdf
然后新建一个vuePdf.vue组件,直接复制粘贴使用即可,样式可以根据自己需求修改,其他不用修改;
<template> <div id="container"> <!-- 上一页、下一页 --> <div class="right-btn"> <!-- 输入页码 --> <div class="pageNum"> <input v-model.number="currentPage" type="number" class="inputNumber" @input="inputEvent()" /> / {{ pageCount }} </div> <div @click="changePdfPage('first')" class="turn">首页</div> <!-- 在按钮不符合条件时禁用 --> <div @click="changePdfPage('pre')" class="turn-btn" : > 上一页 </div> <div @click="changePdfPage('next')" class="turn-btn" : > 下一页 </div> <div @click="changePdfPage('last')" class="turn">尾页</div> </div> <div class="pdfArea"> <!-- // 不要改动这里的方法和属性,下次用到复制就直接可以用 --> <pdf :src="src" ref="pdf" v-show="loadedRatio === 1" :page="currentPage" @num-pages="pageCount = $event" @progress="loadedRatio = $event" @page-loaded="currentPage = $event" @loaded="loadPdfHandler" @link-clicked="currentPage = $event" id="pdfID" ></pdf> </div> <!-- 加载未完成时,展示进度条组件并计算进度 --> <div class="progress" v-if="loadedRatio != 1"> <el-progress type="circle" :width="70" color="#53a7ff" :percentage=" Math.floor(loadedRatio * 100) ? Math.floor(loadedRatio * 100) : 0 " ></el-progress> <br /> <!-- 加载提示语 --> <span>{{ remindShow }}</span> </div> </div> </template> <script> import pdf from "vue-pdf"; export default { components: { pdf, }, data() { return { // ----- loading ----- remindText: { loading: "加载文件中,文件较大请耐心等待...", refresh: "若卡住不动,可刷新页面重新加载...", }, remindShow: "加载文件中,文件较大请耐心等待...", intervalID: "", src: "", // 当前页数 currentPage: 0, // 总页数 pageCount: 0, // 加载进度 loadedRatio: 0, }; }, created() { // 页面加载,拿到路由中的url复制给data中的src this.src = this.$route.query.url; console.log(this.src); }, mounted() { // // 更改 loading 文字 this.intervalID = setInterval(() => { this.remindShow === this.remindText.refresh ? (this.remindShow = this.remindText.loading) : (this.remindShow = this.remindText.refresh); }, 4000); }, methods: { // 页面回到顶部 toTop() { document.getElementById("container").scrollTop = 0; }, // 输入页码时校验 inputEvent() { if (this.currentPage > this.pageCount) { // 1. 大于max this.currentPage = this.pageCount; } else if (this.currentPage < 1) { // 2. 小于min this.currentPage = 1; } }, // 切换页数 changePdfPage(val) { if (val === "pre" && this.currentPage > 1) { // 切换后页面回到顶部 this.currentPage--; this.toTop(); } else if (val === "next" && this.currentPage < this.pageCount) { this.currentPage++; this.toTop(); } else if (val === "first") { this.currentPage = 1; this.toTop(); } else if (val === "last" && this.currentPage < this.pageCount) { this.currentPage = this.pageCount; this.toTop(); } }, // pdf加载时 loadPdfHandler(e) { // 加载的时候先加载第一页 this.currentPage = 1; }, }, destroyed() { // 在页面销毁时记得清空 setInterval clearInterval(this.intervalID); }, }; </script> <style scoped> #container { position: absolute !important; left: 0; right: 0; bottom: 0; top: 50px; background: #f4f7fd; overflow: auto; font-family: PingFang SC; width: 100%; display: flex; /* justify-content: center; */ position: relative; } /* 右侧功能按钮区 */ .right-btn { position: fixed; right: 5%; bottom: 15%; width: 120px; display: flex; flex-wrap: wrap; justify-content: center; z-index: 99; } .pdfArea { width: 900px; margin: 0 auto; } /* ------------------- 输入页码 ------------------- */ .pageNum { margin: 10px 0; font-size: 18px; } /*在谷歌下移除input[number]的上下箭头*/ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none !important; margin: 0; } /*在firefox下移除input[number]的上下箭头*/ input[type="number"] { -moz-appearance: textfield; } .inputNumber { border-radius: 8px; border: 1px solid #999999; height: 35px; font-size: 18px; width: 60px; text-align: center; } .inputNumber:focus { border: 1px solid #00aeff; background-color: rgba(18, 163, 230, 0.096); outline: none; transition: 0.2s; } /* ------------------- 切换页码 ------------------- */ .turn { background-color: #164fcc; opacity: 0.9; color: #ffffff; height: 70px; width: 70px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 5px 0; } .turn-btn { background-color: #164fcc; opacity: 0.9; color: #ffffff; height: 70px; width: 70px; border-radius: 50%; margin: 5px 0; display: flex; align-items: center; justify-content: center; } .turn-btn:hover, .turn:hover { transition: 0.3s; opacity: 0.5; cursor: pointer; } /* ------------------- 进度条 ------------------- */ .progress { position: absolute; right: 50%; top: 50%; text-align: center; } .progress > span { color: #199edb; font-size: 14px; } </style>
点击【查看源文件】
... <el-button type="text" @click="clickView(scope.row)">查看源文件</el-button> ...
查看源文件方法
... //查看源文件 clickView(row){ if((row.fileName).indexOf('.docx') !== -1){ //这里代码是docx文件预览,此处省略 ... }else{ this.loading = this.$loading({ lock: true, text: "正在加载...", spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.6)' }); //接口函数传入id,返回的文件流 getSourceFileById({},row.id).then(res => { var data = res.data var binaryData = []; binaryData.push(data); let url = window.URL.createObjectURL( new Blob(binaryData, { type: "application/pdf;charset=utf-8", }) ); if (url != null && url != undefined && url) { // vue路由跳转并以问号形式携带vue-pdf预览时所需要的pdf地址 this.$router.push({ path: "/dataStandar/knowledgeBase/createBase/vuepdf", query: { //要传的参数 url: url, }, }); this.loading.close() } }) } }, ...