最近公司让做一个关于内容预览的功能
1.刚开始怎么弄
一开始在网上搜集了大量资料,基本上都不符合关于我的要求,不过最后还是找到了,话不多说,直接上关键步骤
1.1 安装docx-preview
html
# 正常安装
npm install docx-preview --save
#如果出现报错,忽略错误,直接安装
npm install docx-preview --legacy-peer-deps
# 解释:--legacy-peer-deps:安装时忽略所有 peerDependencie
1.2 安装babel
html
# 正常安装
npm install --save-dev @babel/core @babel/preset-env babel-loader
#如果出现错误,忽略,直接安装
npm install --save-dev @babel/core @babel/preset-env babel-loader --legacy-peer-deps
1.3安装raw-loader(不确定是否跟该插件有关系)
html
#正常安装
npm install raw-loader
#如果报错,忽略错误,直接安装
npm install raw-loader --legacy-peer-deps
2.配置文件
2.1配置vue.config.js文件
html
# 在该配置文件中找到moudule.exports
# 官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
module.exports = {
#关键的webpack配置
configureWebpack: {
module:{
rules:[
{
#这里我加了raw-loader,不确定是否跟这个配置有关系
test: /\.txt$/,
use: 'raw-loader'
},
{
test: /\.mjs$/,
include: /node_modules/,
type: "javascript/auto",
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
},
}
]
}
}
3.配置请求
3.1若以框架中已经封装好了请求方式,我在这里举个例子:
html
// 导出word功能
export function exportTotal(query) {
return request({
url: '/exportWrod', // 导出文档的接口(java用输出流文件)
method: 'post',
params: query,
responseType: 'blob' // 最重要的步骤,一定要加上这个
})
}
然后再在自己需要预览功能页面中:
3.1.1 建立控件
html
<div v-if="previewDialogVisible">
<el-dialog title="预览" :visible.sync="previewDialogVisible" append-to-body width="50%">
<div ref="file" v-loading="previewLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading" element-loading-background="rgba(0,0,0,0)" style="height: 550px; overflow-y:auto;"></div>
</el-dialog>
</div>
3.1.2 写控件里面的变量
html
data() {
return {
previewDialogVisible: false, // 对话开关
previewLoading:false, // 是否加载
}
}
3.2.3 写一个预览按钮
html
<el-button @click="YL(scope.row)">预览</el-button>
3.2.4 按钮点击方法
关键步骤为,将流文件转化为Blob对象
html
# 在此之前需要自己定一个变量docx
import { renderAsync } from 'docx-preview';
let docx = null;
# 再在created里面
created() {
docx = require('docx-preview');
window.JSZip = require('jszip');
}
#再写自己的方法
YL(val){
this.previewDialogVisible = true;
this.previewLoading = true;
const orderCheckData = {};
orderCheckData.orderNo = val.orderNo;
orderCheckData.time = val.time;
exportTotal(orderCheckData).then(res => {
const blob = new Blob([res]); // 关键步骤
docx.renderAsync(blob,this.$refs.file,null,{
className: 'docx',
inWrapper: true,
ignoreWidth: false,
ignoreHeight: false,
ignoreFonts:false,
breakPages: true,
ignoreLastRenderedPageBreak: true,
experimental: true,
useBase64URL:false,
trimXmlDeclaration: true,
debug: false
})
console.dir("转化完成");
})
.catch((err)=>{
console.dir("报错了");
console.dir(err);
});
},
附原API
html
// renders document into specified element
renderAsync(
document: Blob | ArrayBuffer | Uint8Array, // could be any type that supported by JSZip.loadAsync
bodyContainer: HTMLElement, //element to render document content,
styleContainer: HTMLElement, //element to render document styles, numbeings, fonts. If null, bodyContainer will be used.
options: {
className: string = "docx", //class name/prefix for default and document style classes
inWrapper: boolean = true, //enables rendering of wrapper around document content
ignoreWidth: boolean = false, //disables rendering width of page
ignoreHeight: boolean = false, //disables rendering height of page
ignoreFonts: boolean = false, //disables fonts rendering
breakPages: boolean = true, //enables page breaking on page breaks
ignoreLastRenderedPageBreak: boolean = true, //disables page breaking on lastRenderedPageBreak elements
experimental: boolean = false, //enables experimental features (tab stops calculation)
trimXmlDeclaration: boolean = true, //if true, xml declaration will be removed from xml documents before parsing
useBase64URL: boolean = false, //if true, images, fonts, etc. will be converted to base 64 URL, otherwise URL.createObjectURL is used
renderChanges: false, //enables experimental rendering of document changes (inserions/deletions)
renderHeaders: true, //enables headers rendering
renderFooters: true, //enables footers rendering
renderFootnotes: true, //enables footnotes rendering
renderEndnotes: true, //enables endnotes rendering
debug: boolean = false, //enables additional logging
}): Promise<WordDocument>
/// ==== experimental / internal API ===
// this API could be used to modify document before rendering
// renderAsync = praseAsync + renderDocument
// parse document and return internal document object
praseAsync(
document: Blob | ArrayBuffer | Uint8Array,
options: Options
): Promise<WordDocument>
// render internal document object into specified container
renderDocument(
wordDocument: WordDocument,
bodyContainer: HTMLElement,
styleContainer: HTMLElement,
options: Options
): Promise<void>
3.2 如果没有使用若依框架,则
html
axios({
method: "get",
responseType: "blob", // 因为是流文件,所以要指定blob类型
url: "/exportWOrd", // word下载文件接口
}).then(({ data }) => {
console.log(data); // 后端返回的是流文件
const blob = new Blob([data]); // 把得到的结果用流对象转一下
var a = document.createElement("a"); //创建一个<a></a>标签
a.href = URL.createObjectURL(blob); // 将流文件写入a标签的href属性值
a.download = "出师表.docx"; //设置文件名
a.style.display = "none"; // 障眼法藏起来a标签
document.body.appendChild(a); // 将a标签追加到文档对象中
a.click(); // 模拟点击了a标签,会触发a标签的href的读取,浏览器就会自动下载了
a.remove(); // 一次性的,用完就删除a标签
});
4.java后端代码(主要写Content-Type,只写部分代码)
使用XWPFTemplate写的Word文档
java
// 下载方式
OutputStream out = null; // 输出到客户端
FileInputStream fns = null; // 读取临时文件
ByteArrayOutputStream baos = null; // 读完后的数据放到这里面
FileOutputStream fous = null; // 写到本地(创建新文件)
try {
// 先写本地
fous = new FileOutputStream(outPath); // 创建新文件,此处outPath为输出到本地的文件路径
template.write(fous); // 使用的XWPFTemplate来写的Word文档
out = response.getOutputStream(); // 获取客户端输出流
fns = new FileInputStream(outPath);// 读取已经生成的文件
baos = new ByteArrayOutputStream(); // new一个字节数组输出流
// 循环读取文件
byte[] buffer = new byte[1024]; // 定义缓冲字节数组
int len; // 读取长度
while ((len = fns.read(buffer)) != -1){
baos.write(buffer,0,len); // 读取buffer里面的数据,从0开始,写len个长度。
}
// 给文件起名字
String exportName= "临时文件.docx";
// 对中文进行编码
String str = "attachment;filename="+ URLEncoder.encode(exportName,"UTF-8");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition",str);
// 导出
out.write(baos.toByteArray());
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if (baos != null) {
baos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fns != null) {
fns.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fous != null) {
fous.close();
}
}catch (IOException e){
e.printStackTrace();
}
try {
if (template != null) {
template.close();
}
}catch (IOException e){
e.printStackTrace();
}
}