zoukankan      html  css  js  c++  java
  • 前端vue以模板方式导出word----依赖 docxtemplater

    原理:需要将页面中table导出一个word文件,在本地做好一个word模板,定义好变量,以这个模板文件为导出依赖,将后台获取的变量添加进去。

    需求:将“伦理审查批件”导出为word

    导出word和pdf对实际工作的影响:

      上一篇博客实现了前端导出pdf,但是后来发现,当意见内容特别多的时候,pdf分页会有点问题:

      

      而word会自动处理这种情况:

      

      综上,如果确定导出文件的高度在一页内能搞定,那么用pdf会更简单点,需要多页的话还是用word更适合使用需求。

      导出pdf的原理是 html2canvas 对页面进行截图,再用 jspdf 将截图转为 pdf,所以这种做法一定会导致多页的时候出现上述问题,但是现在好像vue导出pdf大多数使用的都是这个方法,以后有时间再研究下其他的方法可以导出好看点的pdf。

    操作步骤:

    1、下载插件

      npm i docxtemplater jszip-utils file-saver jszip@2.6.1

      注意:jszip的版本是2.6.1,最新版的可能有问题,或者安装 pizzip 替代 jszip

    2、定义word模板:vue3.0将该文件放在public目录下,vue2.0将该文件放在static目录下

    3、引入插件和定义导出函数

    import docxtemplater from 'docxtemplater'
    import JSZipUtils from 'jszip-utils'
    import { saveAs } from 'file-saver'
    import JSZip from 'jszip'
        exportWord: function() {
          let _this = this
          // 读取并获得模板文件的二进制内容
          JSZipUtils.getBinaryContent('approvalNo.docx', function(error, content) {
            if (error) throw error // 抛出异常
            let zip = new JSZip(content) // 创建一个JSZip实例,内容为模板的内容
            let doc = new docxtemplater().loadZip(zip) // 创建并加载docxtemplater实例对象
            doc.setData({ ..._this.approvalNoOrOpinionNoList }) // 设置模板变量的值
            try {
              doc.render() // 用模板变量的值替换所有模板变量
            } catch (error) {
              let e = {
                message: error.message,
                name: error.name,
                stack: error.stack,
                properties: error.properties
              }
              console.log(JSON.stringify({ error: e }))
              throw error // 抛出异常
            }
            // 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
            let out = doc.getZip().generate({
              type: 'blob',
              mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
            })
            // 将目标文件对象保存为目标类型的文件,并命名
            saveAs(out, 'aaa.docx')
          })
        }

      注意:引入路径和传入到模板中的参数

    4、定义按钮点击导出,实际导出效果:

    报错:

    第一种:

    Uncaught Error: Error: Can't find end of central directory : is this a zip file ? If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html
        at XMLHttpRequest.xhr.onreadystatechange

    翻译:

    未捕获的错误:错误:无法找到结束的中央目录:这是一个zip文件吗?如果是,请查看http://stuk.github.io/jszip/documentation/howto/read_zip.html

    在XMLHttpRequest.xhr.onreadystatechange

    解释:················意思是说你路径写错了

    第二种:

    Uncaught Error: InternalError: The filetype for this file could not be identified, is this file corrupted ?
        at XMLHttpRequest.xhr.onreadystatechange

    翻译:

    无法识别此文件的文件类型,此文件是否已损坏?

    在XMLHttpRequest.xhr.onreadystatechange

    解释:················意思是说后缀名doc会有可能出问题,换成docx试试

    页面完整代码:

    <template>
      <div class="approvalNo-or-opinionNo-list">
        <el-button type="primary" size="small" @click="exportWord">点击下载</el-button>
        <div id="pdfDom">
          <table cellspacing="0">
            <caption>
              伦理审查批件
            </caption>
            <tr>
              <td class="key-name">批件号</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.approvalNo }}</td>
            </tr>
            <tr>
              <td class="key-name">项目名称</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.projectName }}</td>
            </tr>
            <tr>
              <td class="key-name">项目来源</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.sponsorName }}</td>
            </tr>
            <tr>
              <td class="key-name">研究单位</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.researchUnit }}</td>
            </tr>
            <tr>
              <td class="key-name">主要研究者</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.personName }}</td>
            </tr>
            <tr>
              <td class="key-name">审查类别</td>
              <td>{{ approvalNoOrOpinionNoList.taskStyle }}</td>
              <td class="key-name">审查方式</td>
              <td>{{ approvalNoOrOpinionNoList.taskType }}</td>
            </tr>
            <tr>
              <td class="key-name">审查日期</td>
              <td>{{ approvalNoOrOpinionNoList.auditDate }}</td>
              <td class="key-name">审查地点</td>
              <td>{{ approvalNoOrOpinionNoList.auditAddress }}</td>
            </tr>
            <tr>
              <td class="key-name">审查委员</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.auditCommittees }}</td>
            </tr>
            <tr>
              <td class="key-name">批准文件</td>
              <td colspan="3">见附件</td>
            </tr>
            <tr>
              <td colspan="4" class="options">
                {{ approvalNoOrOpinionNoList.auditRemark }}
              </td>
            </tr>
            <tr>
              <td class="key-name">年度/定期<br />跟踪审查频率</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.frequency }}</td>
            </tr>
            <tr>
              <td class="key-name">有效期</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.effectiveStartDate }} 至 {{ approvalNoOrOpinionNoList.effectiveEndDate }}</td>
            </tr>
            <tr>
              <td class="key-name">联系人与联系电话</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.sponsorContacts }} {{ approvalNoOrOpinionNoList.sponsorTel }}</td>
            </tr>
            <tr>
              <td class="key-name">伦理委员会</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.ethicsCommittee }}</td>
            </tr>
            <tr>
              <td class="key-name">主任签名</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.directorAutograph }}</td>
            </tr>
            <tr>
              <td class="key-name">日期</td>
              <td colspan="3">{{ approvalNoOrOpinionNoList.todayDate }}</td>
            </tr>
          </table>
        </div>
      </div>
    </template>
    <script>
    import docxtemplater from 'docxtemplater'
    import JSZipUtils from 'jszip-utils'
    import { saveAs } from 'file-saver'
    import JSZip from 'jszip'
    export default {
      data() {
        return {}
      },
      props: {
        approvalNoOrOpinionNoList: {
          type: Object,
          default: {}
        }
      },
      methods: {
        exportWord: function() {
          let _this = this
          // 读取并获得模板文件的二进制内容
          JSZipUtils.getBinaryContent('approvalNo.docx', function(error, content) {
            if (error) throw error // 抛出异常
            let zip = new JSZip(content) // 创建一个JSZip实例,内容为模板的内容
            let doc = new docxtemplater().loadZip(zip) // 创建并加载docxtemplater实例对象
            doc.setData({ ..._this.approvalNoOrOpinionNoList }) // 设置模板变量的值
            try {
              doc.render() // 用模板变量的值替换所有模板变量
            } catch (error) {
              let e = {
                message: error.message,
                name: error.name,
                stack: error.stack,
                properties: error.properties
              }
              console.log(JSON.stringify({ error: e }))
              throw error // 抛出异常
            }
            // 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
            let out = doc.getZip().generate({
              type: 'blob',
              mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
            })
            // 将目标文件对象保存为目标类型的文件,并命名
            saveAs(out, 'aaa.docx')
          })
        }
      }
    }
    </script>
    <style lang="scss">
    .approvalNo-or-opinionNo-list {
      height: 350px;
      overflow-y: auto;
      padding-bottom: 20px;
      border-bottom: 1px solid #ccc;
      > #pdfDom {
        table {
          text-align: center;
          border-bottom: 1px solid #ccc;
           93%;
          margin: 0 auto;
          font-family: '楷体', '楷体_GB2312';
          caption {
            font-size: 16px;
            text-align: center;
            line-height: 46px;
            color: #333;
            font-weight: bold;
          }
          td {
             25%;
            height: 32px;
            color: #666;
            border-left: 1px solid #ccc;
            border-top: 1px solid #ccc;
            padding: 0 6px;
          }
          td:last-child {
            border-right: 1px solid #ccc;
          }
          .key-name {
            color: #333;
            font-weight: 600;
          }
          .options {
            padding: 10px;
            text-align: justify;
            text-indent: 2em;
          }
        }
      }
    }
    </style>
    View Code

    前端vue以数据流方式导出word----借助 jquery

  • 相关阅读:
    Learn Goroutine
    Redis eviction policies
    Hungarian Algorithm
    Prime and Factors
    HDU 2642 Stars
    236. Lowest Common Ancestor of a Binary Tree
    Leetcode 96. Unique Binary Search Trees
    Search in Rotated Sorted Array
    ID Generator
    概率问题
  • 原文地址:https://www.cnblogs.com/wuqilang/p/14085382.html
Copyright © 2011-2022 走看看