docx库Table踩坑

865 阅读2分钟

docx库Table踩坑

background.svg

介绍

最近工作中遇到了需要导出word文档的需求,只是简单的将列表详情的数据导出成word中的表格。
类似于下面的效果:

标题内容
标题内容
标题内容

之后找到了相关的工具库docx
功能强大,他封装了word中的相关模块的构造方法,只需要简单的创建一个对象就可以生成word文档。
其中的一些构造方法有DocumentTableParagraphTextRun等。

正文

接着就正式开始嘎嘎一顿操作。

简单实现

import {
  Document,
  Table,
  TableCell,
  TableRow,
  Paragraph,
  VerticalAlign,
  WidthType,
  TableLayoutType,
} from 'docx'

export default function exportDocx(filename, value) {
  const table = new Table({
    rows: value.reduce((acc, item) => {
      const { key, value } = item
        if (Array.isArray(value)) {
          acc.push(
            ...value.map((item, index) => {
              return new TableRow({
                children: [
                  ...(index == 0 ? [
		    TableCell({
		      rowSpan: value.length,
		      children: [
		        new Paragraph({ text: key }),
		      ],
		      verticalAlign: VerticalAlign.CENTER,
		    }),
		  ] : []),
		  new TableCell({
		    children: [
		      new Paragraph({text: item }),
		    ],
		    verticalAlign: VerticalAlign.CENTER,
		  }),
		]})
	     })
	  )
	} else {
	  acc.push(
	    new TableRow({
	      children: [
		new TableCell({
		  children: [
		    new Paragraph({ text: key }),
		  ],
		  verticalAlign: VerticalAlign.CENTER,
		}),
		new TableCell({
		  children: [
                    new Paragraph({ text: value }),
		  ],
		  verticalAlign: VerticalAlign.CENTER,
		}),
	     ],
	  })
	)
      }
      return acc
    }, [])
  })
}

简单试试:

exportDocx('example.docx', [
  {
    key: "title1",
    value: "value1"
  },
  {
    key: "title2",
    value: [
      "value2-1",
      "value2-2",
      "value2-3"
    ]
  }
])

docx-1.jpg

看着没啥问题,但是他没有撑满整个文档。
Table加个宽度。

  • 因为存在一个标题存在多条数据的情况,所以需要使用到rowSpan,和htmltable同理。
  • verticalAlign,内容垂直对齐方式。
  • Paragraph段落内容,可以当成文字使用。
  • TableRow,等同于html的tr
  • TableCell,等同于html的td

添加宽度

new Table({
  width: {
    type: WidthType.PERCENTAGE,
    size: 100 
  }
})

docx-2.jpg

  • WidthType 是一些宽度类型的枚举值AUTO(default) | PERCENTAGE(百分比) | NIL(空) | DXA(二十分之一点)
  • 关于这个DXA单位,大致看下这里

看着没问题。 再试试多加点内容的情况👍。

exportDocx('example.docx', [
  {
    key: "title1",
    value: "value1".repeat(50)
  },
  {
    key: "title2",
    value: [
      "value2-1",
      "value2-2",
      "value2-3"
    ]
  }
])

docx-3.jpg

有点问题,文字多的那一栏,宽度超出了太多。
并且在钉钉里看到的预览效果是这样的。

docx-4.jpg

emoji-1.jpg

在仓库里逛了会儿issue找到了对应的问题。
解决办法-1
解决办法-2

  • 不再使用百分比宽度,而是使用DXA宽度。
  • Table的宽度设置成0,并且规定其列数和列宽。
  • 设置TablelayoutFIXED
new Table({
  layout: TableLayoutType.FIXED,
	columns: 3,
	width: 0, 
	columnWidths: [3213, 3213, 3212] // total page width is 9638 DXA for A4 portrait
})

关于上面宽度设置成0的问题,打开word文档查看:

表格大小.jpg 虽然指定宽度的按钮未被选中,但是在钉钉中依旧生效了。
将其指定为0保证完全不受影响。
设置TablelayoutFIXED,表示固定尺寸,防止单元格被压缩变形。
关于DXA的问题,个人猜测是可能百分比不被识别。

最后附上完整的例子。

docx-5.jpg

结束

简单记录下此次使用docx的踩坑。