前端文件流文件预览下载(支持excel与pdf)
前端实现
前提,不要引入mock,不然会有bug!!!!
在开发过程中,产品提出需求,希望文件可以先在线预览需要下载的文件,但又不希望以网址的方式返给前端,以文件流的形式返给前端,这样以保证安全性。
经过在各种网站上流浪几个小时后,确定使用iframe与xlsx的方案来分别预览pdf
与表格
下面是代码及介绍
<!-- 预览弹框 -->
<el-dialog
title="预览"
top="8vh"
width="70%"
:visible.sync="dialogPreVisible"
@close="()=>{pdf = ''}"
>
<iframe
style="width: 100%; height: 450px"
frameborder="0"
width="100%"
height="620px"
:src="pdf"
v-if="pdf"
type="application/x-google-chrome-pdf"
ref="previewFrame"
></iframe>
<div
class="table-html-wrap"
v-if="!pdf"
style="width: 100%; height: 420px;overflow: auto;"
id="tableHtml"
></div>
</el-dialog>
首先使用了一个弹框进行预览,v-if切换pdf和excel,接下来就是预览部分js
// 预览
async doPreview(row, col) {
// row col 为发送请求的参数
const res = await getPdf(row[`${col}Id`]);
if (
res.fileType !== "pdf" &&
res.fileType !== "xlsx" &&
res.fileType !== "xls"
) {
this.$message.warning("只支持pdf与excel格式的文件预览");
return;
}
let typeList = {
pdf: "application/pdf",
xls: "application/vnd.ms-excel",
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
};
const blob = new Blob([res], { type: typeList[res.fileType] });
if (res.fileType === "pdf") {
this.pdf = URL.createObjectURL(blob);
} else {
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target.result);
let workbook = XLSX.read(data, { type: "array" }); // 解析数据
this.tableToHtml(workbook);
};
reader.readAsArrayBuffer(blob);
}
this.dialogPreVisible = true;
},
res.fileType这个信息并不是后端返回的(文件的后缀及格式),而是在前端请求拦截处统一加上的,如下
service.interceptors.response.use(
(response) => {
const res = response.data;
// console.log(response, '兰拦截')
if (response.config.responseType == "blob") {
if (response.headers.get("Content-Disposition")) {
let type = response.headers.get("Content-Disposition");
// console.log( type.substring(type.lastIndexOf('.') + 1))
res.fileType = type.substring(type.lastIndexOf(".") + 1);
}
return res;
}
// loadingInstance.close()
if ( res&&res.code !== "000000") {
// console.log(res,'res')
Message({
message: res.mesg || "Error",
type: "error",
duration: 5 * 1000,
});
// console.log(res, '222')
}
// console.log(res,'res1111');
return res
},
- 使用了response.headers.get("Content-Disposition");读取后端返回的响应头(这步需要后端配合)
- 枚举文件格式对应的blob格式,在此我也就不为了这些水字数了,具体其他格式可参考mdn网站点击闪现
- 然后就可以res.fileType拿到文件的格式,然后根据文件格式设置对应的配置
下面是pdf预览代码的解释
const blob = new Blob([res], { type: typeList[res.fileType] });
Blob()
构造函数可以通过其他对象创建 blob。
this.pdf = URL.createObjectURL(blob);
下面是表格预览代码的解释
npm i xlsx 或者 yarn add xlsx
调用 URL.createObjectURL()
方法,将 blob 转换为一个 url
,然后将url传入ifram的src中,pdf的预览就完成了
const reader = new FileReader();
创建一个FileReader对象,FileReader对象允许Wb应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用fi1e或B1ob对象指定要读取的文件或数据。
reader.onload = (e) => {
const data = new Uint8Array(e.target.result);
let workbook = XLSX.read(data, { type: "array" }); // 解析数据
this.tableToHtml(workbook);
};
reader.readAsArrayBuffer(blob);
reader.readAsArrayBuffer(blob)将blob类型转换为arrayBuffer,然后在reader.onload的函数用e.target.result拿到被转换后的结果,然后使用ew Uint8Array()构造函数将流格式的返回值转换,再使用XLSX.read(data, { type: "array" })读取结果,最后调用this.tableToHtml()函数渲染表格
tableToHtml(workbook) {
var worksheet = workbook.Sheets[workbook.SheetNames[0]];
// var innerHTML = XLSX.utils.sheet_to_html(worksheet);
if (document.querySelector("#tableHtml")) {
document.querySelector("#tableHtml").innerHTML =
XLSX.utils.sheet_to_html(worksheet);
document.querySelector(".table-html-wrap table");
let trs = document.querySelectorAll("tr");
trs.forEach((tr) => {
if (!tr.innerText.trim()) {
tr.remove();
}
});
document.querySelector(".el-dialog__body").style.overflowX = "auto";
}
let tds = document.querySelectorAll("td");
},
-
获取dom,tableHtml,并使用 XLSX.utils.sheet_to_html(worksheet)将xlsx读取的结果渲染到页面上
let trs = document.querySelectorAll("tr"); trs.forEach((tr) => { if (!tr.innerText.trim()) { tr.remove(); } }); document.querySelector(".el-dialog\_\_body").style.overflowX = "auto";
这段代码是处理,预览出来的结果会出现空格的问题
转载自:https://juejin.cn/post/7241096652919472186