添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
web前端导出word文档

web前端导出word文档

2023年05月30日 阅读:394 字数:1179 阅读时长:3 分钟

项目有个需求要前端预览和导出word文档,记录下技术选型和功能实现

项目上有一个导出word文档的需求,由于有可视化图表,后端导出会比较麻烦,而且前端也需要把word报告展示出来。

所以在前端做预览和导出,记录下技术选型以及实现方案。

2.Word导出

2.1.docx

docx - Generate .docx documents with JavaScript

  • 需要使用指定的api生成和修改.docx文件
  • 功能强大,除了标题、段落、图片等基础,还支持封面、页眉、页脚、分页等等
  • import { Document, Packer, Paragraph, TextRun } from "docx";
    import { saveAs } from 'file-saver'
    const doc = new Document({
      sections: [
          properties: {},
          children: [
            new Paragraph({
              children: [
                new TextRun("Hello World"),
                new TextRun({
                  text: "Foo Bar",
                  bold: true
                new TextRun({
                  text: "\tGithub is the best",
                  bold: true
    Packer.toBlob(doc).then((blob) => {
      saveAs(blob, "example.docx");
      console.log("Document created successfully");
    

    2.2.html-docx-js

    html-docx-js - npm (npmjs.com)

  • 可以根据html导出word
  • 图片、canvas需要转换成Data URL的图片
  • 不支持封面、页眉页脚等功能
  • import { saveAs } from 'file-saver'
    import htmlDocx from 'html-docx-js'
    // 导出图片的格式
    const IMAGE_TYPE = 'image/jpeg'
    // 导出图片的质量
    const IMAGE_QUALITY = 0.8
     * HTML导出Docx
     * @param {String} params.element 要导出的元素选择器
     * @param {String} params.styleString 样式字符串
     * @param {String} params.orientation 页面方向 portrait:竖向、landscape:横向
     * @param {String} params.filename 导出文件名称
    function exportHtmlToDocx({ element, styleString, margins, orientation = 'portrait', filename = 'htmlDocx' }) {
      const html = generateContent(element)
      const content = `
            <style>${styleString ? styleString.replace(/(\s{2,}|\n)/g, '') : ''}</style>
          </head>
          <body>${html}</body>
        </html>
      const converted = htmlDocx.asBlob(content, { orientation, margins })
      saveAs(converted, filename)
     * 生成导出的html字符串
     * @param {String} element 要导出的元素选择器
     * @returns {String}
    function generateContent(element) {
      const sourceElement = document.querySelector(element)
      let cloneElement = sourceElement.cloneNode(true)
      cloneElement = convertImagesToBase64(cloneElement, sourceElement)
      cloneElement = convertCanvasToBase64(cloneElement, sourceElement)
      return cloneElement.innerHTML
     * 转换图片地址为Data URL
     * @param {Element} cloneElement 拷贝要导出的元素
     * @param {Element} sourceElement 要导出的元素
     * @returns {Element}
    function convertImagesToBase64(cloneElement, sourceElement) {
      const sourceImages = sourceElement.querySelectorAll('img')
      const cloneImages = cloneElement.querySelectorAll('img')
      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')
      sourceImages.forEach((imgElement, index) => {
        const width = imgElement.width
        const height = imgElement.height
        // preparing canvas for drawing
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        canvas.width = width
        canvas.height = height
        ctx.drawImage(imgElement, 0, 0, width, height)
        // by default toDataURL() produces png image, but you can also export to jpeg
        // checkout function's documentation for more details
        const dataURL = canvas.toDataURL(IMAGE_TYPE, IMAGE_QUALITY)
        // 替换拷贝的元素而不是源图片
        const replaceElement = cloneImages[index]
        replaceElement.setAttribute('src', dataURL)
      canvas.remove()
      return cloneElement
     * 转换canvas画布为img + Base64 URL
     * @param {Element} cloneElement 拷贝要导出的元素
     * @param {Element} sourceElement 要导出的元素
     * @returns {Element}
    function convertCanvasToBase64(cloneElement, sourceElement) {
      const sourceCanvas = sourceElement.querySelectorAll('canvas')
      const cloneCanvas = cloneCanvas.querySelectorAll('canvas')
      sourceCanvas.forEach((canvasElement, index) => {
        const dataURL = canvasElement.toDataURL(IMAGE_TYPE, IMAGE_QUALITY)
        const imgElement = document.createElement('img')
        imgElement.src = dataURL
        const replaceElement = cloneCanvas[index]
        // 把canvas元素替换成img
        replaceElement.parentNode.replaceChild(imgElement, replaceElement)
      return cloneElement
    export default exportHtmlToDocx
    
    import exportHtmlToDocx from 'export-html-to-docx.js'
    exportHtmlToDocx({
      element: '#htmlDocx',
      styleString: 'table td{border: 1px solid #e2e2e2}',
      margin: { // 页边距
        top: 1440, // eq 2.54cm
        right: 1440,
        bottom: 1440,
        left: 1440
      orientation: 'portrait',
      filename: 'word报告'
    

    2.2.1.常见问题

  • 样式不生效,不支持多个选择器设置样式:每个标签只使用一个选择器,通过不同的选择器设置样式规则,如正常段落、首行缩进段落、首行缩进且加粗段落
  • <p class="para-indent">首行缩进</p>
    <p class="para-bold">文本加粗</p>
    <p class="para-indent-bold">首行缩进并加粗</p>
    .para{font-size:12pt;}
    .para-indent{font-size:12pt;text-indent:2em;}
    .para-bold{font-size:12pt;font-weight:bold;}
    .para-indent-bold{font-size:12pt;text-indent:2em;font-weight:bold;}
  • 表格内的字体无法设置宋体:给文本嵌套一层P标签
  • <table>
          <p class="para-bold">表格内的段落</p>
    </table>
  • 表格边框样式设置
  • 不能这样(边框样式会有问题):

    table {
    	border-top: 1px solid #000;
    	border-left: 1px solid #000;
    table td,
    table th {
    	border-right: 1px solid #000;
    	border-bottom: 1px solid #000;
    

    要用下面这种:

    table {
      border: 1px solid #000000;
      border-collapse: collapse;
      border-spacing: 0;
    table td,
    table th {
      border: 1px solid #000000;
    
  • 导出图片、Canvas为空:等待图片、DOM加载完成再进行导出
  • 2.3.html-docx

    html-docx - npm (npmjs.com)

    这是基于html-docx-js实现的,封装了一些常用的方法,比如上面的canvas转换、文档封面、页眉页脚等。

  • 图片使用网络地址,如果要转成Data URL,需要自己改逻辑
  • 文档封面、页眉页脚、分页等是通过修改html-docx-js源码实现的
  • import HtmlToDocx from 'html-docx'
    HtmlToDocx({
        exportElement: '#html-content', // 需要转换为word的html标签
        exportFileName: 'list.docx', // 转换之后word文档的文件名称
        StringStyle: '', // css样式以字符串的形式插入进去
        margins:{top: 1440,right: 1440,bottom: 1440,left: 1440,header: 720,footer: 720} // word的边距配置
    

    3.HTML预览

    这里的预览不是使用Office的服务来预览Word文档,只是用HTML展示出来。

    尽量使用原生而不是UI库,因为UI库不好控制组件内的层级、样式等,可能影响最终的导出。

    页面尺寸可以参考:https://github.com/cognitom/paper-css

    字号换算:(53条消息) Word字体大小对照换算表(字号、磅、英寸、像素)_QAQ_King的博客-CSDN博客

    图片、Canvas导出:根据HTML展示的图片尺寸导出

    (0)