Timeless
花开成景,花落成诗
项目有个需求要前端预览和导出word文档,记录下技术选型和功能实现
项目上有一个导出word文档的需求,由于有可视化图表,后端导出会比较麻烦,而且前端也需要把word报告展示出来。
所以在前端做预览和导出,记录下技术选型以及实现方案。
docx - Generate .docx documents with JavaScript
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");
});
html-docx-js - npm (npmjs.com)
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 = `
<html>
<head>
<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 = cloneElement.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报告'
})
<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;}
<table>
<tr>
<td>
<p class="para-bold">表格内的段落</p>
</td>
</tr>
</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;
}
这是基于html-docx-js实现的,封装了一些常用的方法,比如上面的canvas转换、文档封面、页眉页脚等。
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的边距配置
})
这里的预览不是使用Office的服务来预览Word文档,只是用HTML展示出来。
尽量使用原生而不是UI库,因为UI库不好控制组件内的层级、样式等,可能影响最终的导出。
页面尺寸可以参考:https://github.com/cognitom/paper-css
字号换算:(53条消息) Word字体大小对照换算表(字号、磅、英寸、像素)_QAQ_King的博客-CSDN博客
图片、Canvas导出:根据HTML展示的图片尺寸导出
Power by Node.js + Nuxt.js,由 腾讯云提供服务, 已经稳稳地存活了 8年95天
Copyright © 2018 - 2026 Timeless. All rights reserved.桂ICP备18003656号-1桂公网安备45092102000147号
评论