Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出
- 预览
- 安装插件
- 示例代码
- 项目目录结构截图
- 实际效果截图
- 动态渲染 .docx 文档(带图片),预览、导出
- 安装插件
- docx 模板文件内容
- 完整代码
预览
必须是 .docx 文档,别的类型的文档请自行研究实现
- 通过 vue-office/docx 插件预览 docx 文档
- 通过 vue-office/excel 插件预览 excel 文档
- 通过 vue-office/pdf 插件预览 pdf 文档
安装插件
npm install @vue-office/docx vue-demi
示例代码
<template>
<VueOfficeDocx :src="docx" @rendered="rendered"></VueOfficeDocx>
</template>
<script setup lang="ts">
import VueOfficeDocx from "@vue-office/docx";
import "@vue-office/docx/lib/index.css";
import { ref } from "vue";
const docx = ref("../../public/01.docx");
const rendered = () => {
console.log("加载完毕...");
};
</script>
<style lang="scss" scoped></style>
项目目录结构截图
实际效果截图
动态渲染 .docx 文档(带图片),预览、导出
安装插件
npm install docxtemplater
npm install docxtemplater-image-module-free
npm install pizzip
npm install file-saver
docx 模板文件内容
- vue3项目把该模板 docx 文件放 public 文件夹里面
完整代码
<template>
<div class="common-layout">
<el-container style="height: 100vh">
<el-aside
style="
width: 200px;
background: rgb(216.8, 235.6, 255);
padding: 80px 0 0 30px;
"
>
<el-button type="danger" @click="wordWrite(content)">写入</el-button>
<el-button type="danger" @click="wordExport(content)">导出</el-button>
<div></div>
</el-aside>
<el-container>
<el-header style="background: rgb(197.7, 225.9, 255)">
<H2>
Vue3 项目通过 docxtemplater 插件动态渲染 .docx
文档(带图片)预览,并导出</H2
>
</el-header>
<el-main>
<template v-if="!isShow">
<h3>准备写入 docx 文件内容</h3>
<div>
<p>姓名:{{ content.name }}</p>
<p>年龄:{{ content.age }}</p>
<p>性别:{{ content.gender }}</p>
<p>学历:{{ content.education }}</p>
<p>个人简介:{{ content.introduction }}</p>
<p>
头像:
<img :src="content.avatar" alt="头像" />
</p>
</div>
</template>
<div class="m-4">
<!-- docx 文件预览插件 -->
<VueOfficeDocx :src="docx" v-if="isShow"></VueOfficeDocx>
</div>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import Docxtemplater from "docxtemplater";
import ImageModule from "docxtemplater-image-module-free";
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils";
import { saveAs } from "file-saver";
import VueOfficeDocx from "@vue-office/docx"; // 导入预览插件
import "@vue-office/docx/lib/index.css"; // 导入预览插件样式
const isShow = ref(false); // 预览组件状态
const docx = ref("../../public/03.docx"); // 导入 docx 模板文件
import img from "@/assets/01.jpg"; // 导入本地图片
// 准备写入内容
const content = ref({
name: "张三",
age: 25,
gender: "男",
education: "小学",
introduction:
"我是一个热爱学习的学生,喜欢阅读各种类型的书籍,同时也喜欢参加各种活动,比如参加比赛、组织活动等等。",
avatar: img,
});
/**
* 生成文档内容
* @param docData 准备写入内容
*/
const GenerateADocument = (docData) => {
return new Promise((resole, reject) => {
const loadFile = function loadFile(url: any, callback: any) {
PizZipUtils.getBinaryContent(url, callback);
};
loadFile(docx.value, function (error: any, content: any) {
if (error) {
reject(new Error("模板文件未找到"));
}
// 处理图片
let opts: any = {};
opts.centered = false;
opts.fileType = "docx";
opts.getImage = function (tagValue: any) {
return new Promise(function (resolve, reject) {
PizZipUtils.getBinaryContent(
tagValue,
function (error: any, content: any) {
if (error) {
return reject(error);
}
return resolve(content);
}
);
});
};
opts.getSize = function () {
//这里是生成的word文件里图片的宽和高
// 可以根据自己的需要进行修改,获取图片实际的宽和高,然后返回
return [255, 195];
};
let imageModule = new ImageModule(opts);
var zip = new PizZip(content);
let doc = new Docxtemplater()
.loadZip(zip)
.attachModule(imageModule)
.compile();
doc.resolveData(docData).then(function () {
doc.render();
let out = doc.getZip().generate({
type: "blob",
mimeType:
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
if (out) {
resole(out);
} else {
reject(new Error("文件生成失败"));
}
});
});
});
};
/**
* 写入方法
* @param docData 准备写入内容
*/
const wordWrite = (docData) => {
GenerateADocument(docData)
.then((res) => {
docx.value = URL.createObjectURL(res);
isShow.value = true;
})
.catch((err) => {
console.log(err, "err");
});
};
/**
* 导出方法
* @param docData 准备写入内容
*/
const wordExport = (docData) => {
GenerateADocument(docData)
.then((res) => {
saveAs(res, "测试文件" + ".docx");
})
.catch((err) => {
console.log(err, "err");
});
};
</script>
vue-office 插件预览的时候文件中表格样式被破坏的问题正在研究。