在项目中比如要对上传的文件进行预览,这时前端通常采用的是使用各种库来解决这个问题。这里推荐一个库vue-office
,vue-office是一站式解决(docx、.xlsx、pdf)预览的vue组件库。
可以看出这个组件库还是有些缺陷的,比如docx的艺术字体、excel的多种数据格式解析不准确的问题,但普通的预览是没什么问题的。
为什么基本找不到doc或xls的在线预览,首先doc和xls是07版本前的格式,其次docx和xlsx是采用XML
的开放文件格式进行存储,解析更容易。所以市面上基本都是docx和xlsx更容易找到方案,要能够预览doc和xls一般要花费较大的成本。
相对于文档和表格pdf的库是比较多的,以下为使用vue-office/pdf
的示例:
<template>
<vue-office-pdf
:src="pdf"
@rendered="renderedHandler"
@error="errorHandler"
/>
</template>
<script>
//引入VueOfficePdf组件
import VueOfficePdf from '@vue-office/pdf'
export default {
components: {
VueOfficePdf
},
data() {
return {
pdf: 'http://static.shanhuxueyuan.com/test.pdf' //设置文档地址,可以是base64
}
},
methods: {
renderedHandler() {
console.log("渲染完成")
},
errorHandler() {
console.log("渲染失败")
}
}
}
</script>
这个很简单直接放链接或base64编码就可以,这个是pdf实际就是基于pdfjs这个库,但在比较老的浏览器中兼容性并不好,检查是否支持“||=”,如果支持就直接使用vue-office/pdf
这个库,如果不支持那么我们直接使用[email protected]
这个库。
如果要对pdf进行放大缩小为了性能和用户友好,我们先把canvas画面放大,然后再通过css把盒子缩小,直接控制盒子的缩放就行,这样一来就不用重新渲染同时保证了画质的清晰度,一定程度上提升了性能。
使用示例如下:
<template>
<div class="pdfcontainer">
<div
class="pdfcanvas"
ref="pdfCanvasContainer"
:style="'transform:scale(' + canvasScale + ')'"
></div>
<div class="zoom">
<i class="el-icon-zoom-out cursor" @click="zoom('out')"></i>
<i class="el-icon-zoom-in cursor" @click="zoom('in')"></i>
</div>
</div>
</template>
<script>
import { getDocument } from "pdfjs-dist";
export default {
name: "PdfViewer",
props: {
src: {
type: String,
},
},
data() {
return {
scale: 3,
canvasScale: 0.5,
};
},
mounted() {
this.loadPdf();
},
methods: {
/**
* @description: 加载pdf
*/
loadPdf() {
let base64Data = this.src.replace(/^data:application\/pdf;base64,/, "");
let pdfData = window.atob(base64Data);
let arrayBuffer = new Uint8Array(pdfData.length);
for (let i = 0; i < pdfData.length; i++) {
arrayBuffer[i] = pdfData.charCodeAt(i);
}
const loadingTask = getDocument({ data: arrayBuffer });
loadingTask.promise.then((pdf) => {
const numPages = pdf.numPages;
const canvasContainer = this.$refs.pdfCanvasContainer;
canvasContainer.innerHTML = ""; // 清空容器
for (let pageNumber = 1; pageNumber <= numPages; pageNumber++) {
pdf.getPage(pageNumber).then((page) => {
const viewport = page.getViewport(this.scale);
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
canvas.height = viewport.height || page.view[3];
canvas.width = viewport.width || page.view[2];
// 将canvas添加到容器中
canvasContainer.appendChild(canvas);
// 渲染PDF到canvas
const renderContext = {
canvasContext: context,
viewport: viewport,
};
page.render(renderContext);
});
}
});
},
/**
* @description: 缩放
* @param {String} type 类型
*/
zoom(type) {
if (type) {
if (type === "out" && this.canvasScale.toFixed(2) > 0.1) {
this.canvasScale -= 0.05;
} else if (type === "in") {
this.canvasScale += 0.05;
}
}
},
},
};
</script>
<style scoped>
.pdfcontainer {
position: relative;
}
.pdfcanvas {
position: absolute;
top: 12px;
left: 0;
right: 0;
bottom: 0;
max-width: 100%;
max-height: 100%;
}
.scale {
position: fixed;
bottom: 24px;
right: 24px;
font-size: 24px;
}
.cursor {
margin: 24px;
cursor: pointer;
}
</style>
这个目前就使用vue-office/docx
就能支持,在老本版中浏览器中也能使用,使用示例如下:
<template>
<vue-office-docx
:src="docx"
style="height: 100vh;"
@rendered="renderedHandler"
@error="errorHandler"
/>
</template>
<script>
//引入VueOfficeDocx组件
import VueOfficeDocx from '@vue-office/docx'
//引入相关样式
import '@vue-office/docx/lib/index.css'
export default {
components: {
VueOfficeDocx
},
data() {
return {
docx: 'http://static.shanhuxueyuan.com/test6.docx' //设置文档网络地址,可以是相对地址,也可以是base64
}
},
methods: {
renderedHandler() {
console.log("渲染完成")
},
errorHandler() {
console.log("渲染失败")
}
}
}
</script>
这个目前就使用vue-office/excel就能支持,在老本版中浏览器中也能使用,使用示例如下:
<template>
<vue-office-excel
:src="excel"
style="height: 100vh;"
@rendered="renderedHandler"
@error="errorHandler"
/>
</template>
<script>
//引入VueOfficeExcel组件
import VueOfficeExcel from '@vue-office/excel'
//引入相关样式
import '@vue-office/excel/lib/index.css'
export default {
components: {
VueOfficeExcel
},
data() {
return {
excel: 'http://static.shanhuxueyuan.com/demo/excel.xlsx'//设置文档地址,或base64
}
},
methods: {
renderedHandler() {
console.log("渲染完成")
},
errorHandler() {
console.log("渲染失败")
}
}
}
</script>
图片直接使用img标签就行啦
以上就是在线预览的一些方案啦,有更好的方式欢迎评论留言讨论。