Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出

Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出

预览

必须是 .docx 文档,别的类型的文档请自行研究实现

  • 通过 vue-office/docx 插件预览 docx 文档
  • 通过 vue-office/excel 插件预览 excel 文档
  • 通过 vue-office/pdf 插件预览 pdf 文档

安装插件

js 复制代码
npm install @vue-office/docx vue-demi

示例代码

html 复制代码
<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 文档(带图片),预览、导出

安装插件

js 复制代码
npm install docxtemplater
npm install docxtemplater-image-module-free
npm install pizzip
npm install file-saver

docx 模板文件内容

  • vue3项目把该模板 docx 文件放 public 文件夹里面

完整代码

html 复制代码
<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 插件预览的时候文件中表格样式被破坏的问题正在研究。

相关推荐
空中湖26 分钟前
文档极速转换器 - 免费批量Word转PDF工具
pdf·word
前端小白从0开始2 小时前
Vue3项目实现WPS文件预览和内容回填功能
前端·javascript·vue.js·html5·wps·文档回填·文档在线预览
難釋懷3 小时前
Vue解决开发环境 Ajax 跨域问题
前端·vue.js·ajax
挑战者6668884 小时前
vue入门环境搭建及demo运行
前端·javascript·vue.js
程序猿ZhangSir5 小时前
Vue3 项目的基本架构解读
前端·javascript·vue.js
亲亲小宝宝鸭6 小时前
写了两个小需求,终于搞清楚了表格合并
前端·vue.js
Face6 小时前
路由Vue-router 及 异步组件
前端·javascript·vue.js
风之舞_yjf8 小时前
Vue基础(14)_列表过滤、列表排序
前端·javascript·vue.js
疯狂的沙粒8 小时前
uni-app 项目支持 vue 3.0 详解及版本升级方案?
前端·vue.js·uni-app
Lhuu(重开版9 小时前
Vue:Ajax
vue.js·ajax·okhttp