富文本编辑器html内容转word:html

您所在的位置:网站首页 网页转换word图片不显示 富文本编辑器html内容转word:html

富文本编辑器html内容转word:html

2024-01-02 15:04| 来源: 网络整理| 查看: 265

这是我参与「掘金日新计划 · 4 月更文挑战」的第 1 天,活动详情:juejin.cn/post/721806…

👉🏻 本文代码地址 👉🏻 线上预览效果

前言

我们公司目前在做基于tiptap的在线协同文档,最近需要做导出 pdf、word 需求。

导出 word 文档使用的是html-docx-js-typescript,是用 typescript 重写了一下html-docx-js,可以看到最近的提交记录是 2016 年,貌似已经不维护了,很多 Issues 没人管。

html-docs-js.png

实在找不到其他的 html 转 word 的插件,最后只能使用它来处理,我把我在使用过程中遇到的问题一一列出来,就有了这篇避坑指南。

关于pdf和图片的导出,一文搞定前端html内容转图片、pdf和word等文件

使用说明

安装

安装html-docx-js-typescript,同时安装FileSaver用于浏览器端保存文件。

npm install html-docx-js-typescript file-saver --save-dev npm install @types/html-docx-js @types/file-saver --dev

使用方法

参考官方示例

使用过程遇到的问题及处理方案 字体加粗不生效、字体背景颜色不生效处理

字体加粗和标记文本元素标签需要替换为和标签

const innerHtml = cloneEle.innerHTML // strong在word中不生效问题 .replace(//g, '') .replace(//g, '') // 背景色不生效问题 .replace(/ { Array.from({ length: 6 }).forEach((_, index) => (cloneEle.querySelectorAll(`h${index + 1}`) as unknown as HTMLElement[]).forEach((h) => { h.innerText = (h.children[0] as HTMLElement).innerText h.style.fontSize = '' }) ) } 图片下多出一个白框

Prosemiror-images上传图片后,会在图片后面生成.ProseMirror-separator这个标签,我们在导出时只需要删除它即可。

const removeWhiteBox = (cloneEle: HTMLElement) => { const separators: NodeListOf = cloneEle.querySelectorAll( '.ProseMirror-separator' ) separators.forEach((separator) => separator.parentElement?.removeChild(separator) ) } 列表 ul、ol

在开始处理之前,先介绍一个插入 DOM 的 API insertAdjacentElement。

在 vue、react 这些框架的盛行,基本上我们已经不会再用到 DOM 操作,不过可以了解一下,万一以后用得到呢。

// 将给定元素element插入到调用的元素的某个位置 element.insertAdjacentElement(position, element)

参数position可以是以下位置

'beforebegin': 插入元素之前,类似 insertBefore 'afterbegin': 插入元素第一个 children 之前,类似 prepend 'beforeend': 插入元素最后一个 children 之后,类似 appendChild 'afterend': 插入元素之后,类似 insertAfter

接着我们看一下列表这部分的修改,由于我们项目功能上的需求,列表是使用 div 标签来改造的,所以需要将 div 标签转为 ul/ol,下面是我的实现

const changeDiv2Ul = (div: HTMLElement | Element, parent?: HTMLElement | Element) => { const kind = div.getAttribute('data-list-kind') const ul = kind === 'ordered' ? document.createElement('ol') : document.createElement('ul') const li = document.createElement('li') // 去除margin 不然在word中会偏移 !parent && (ul.style.margin = '0') li.innerHTML = div.innerHTML ul.appendChild(li) parent ? parent.insertAdjacentElement('afterend', ul) : div.insertAdjacentElement('afterend', ul) div.parentElement?.removeChild(div) li.querySelectorAll('.list-marker').forEach((marker) => marker.parentElement?.removeChild(marker)) // 内容区域 li.querySelectorAll('.list-content').forEach((content) => { const span = document.createElement('span') span.innerHTML = (content.firstChild as HTMLElement).innerHTML content.insertAdjacentElement('beforebegin', span) if (content.querySelectorAll('.prosemirror-flat-list').length) { content.querySelectorAll('.prosemirror-flat-list').forEach((div) => changeDiv2Ul(div, content)) } content.parentElement?.removeChild(content) }) } cloneEle.querySelectorAll('.prosemirror-flat-list').forEach((div) => changeDiv2Ul(div)) 复选框 checkbox

复选框 checkbox 的处理,首先考虑的是转为来处理,结果转完后并没有显示复选框;

接着又想着用 span 标签生成一个方框,,这样总能显示了吧!结果依然不行。

正当我想不到办法的时候,突然灵机一动,可不可以把 word 转成 html 后看看 checkbox 最终会显示成啥样呢?

于是通过在线 word 转 html将 word 转为 html 后,看到复选框对应的 html 内容为,改一下吧。

const span = document.createElement('span') span.innerHTML = `` marker.insertAdjacentElement('beforebegin', span) marker.parentElement?.removeChild(marker)

转成 word 后,复选框的选中和取消功能也能正常使用。

附件导出、多维表等 iframe 内容

参考了一下钉钉文档

dingding-fujian.png

这样就很好改了,只需要把附件对应的节点内容,改为链接即可。

cloneEle.querySelectorAll('.attachment-node-wrap').forEach((attach) => { const title = `请至One文档查看附件《${attach.getAttribute('name')}》` const anchorId = attach.parentElement?.getAttribute('data-id') const a = document.createElement('a') a.target = '_blank' a.href = `${location.href}&anchor=${anchorId}` a.innerHTML = `${title}` attach.insertAdjacentElement('beforebegin', a) attach.parentElement?.removeChild(attach) }) CSS 问题

8 月 30 号更新

项目在本地运行时,通过 document.head.querySelectorAll('style') 便可以拿到所有样式信息。但是一旦打包上线,此时的样式文件都是通过外链的形式引入,以上获取 CSS 样式的代码就会获取不到。

css-link.png

修改如下:

// 获取远程css资源 转为text文本 const handleCssStream = async (result: Response) => { if (!result.body) return '' const reader = result.body.getReader() const stream = await new ReadableStream({ start(controller) { // The following function handles each data chunk function push() { // "done" is a Boolean and value a "Uint8Array" reader.read().then(({ done, value }) => { // If there is no more data to read if (done) { controller.close() return } // Get the data and send it to the browser via the controller controller.enqueue(value) // Check chunks by logging to the console push() }) } push() }, }) const text = await new Response(stream, { headers: { 'Content-Type': 'text/html' }, }).text() return text } /** * 处理css * 线上环境 * 本地环境 */ const handleCss = async () => { const styles = document.head.querySelectorAll('style') const links = document.head.querySelectorAll('link[type="text/css"]') // @ts-ignore const remoteCSSPromise = [...links].map((link) => fetch(link.href)) const remoteCSSResult = await Promise.allSettled(remoteCSSPromise) const remoteCSSStreamPromise = remoteCSSResult.map((item) => { // @ts-ignore const { status, value } = item if (status === 'fulfilled') return handleCssStream(value) }) const remoteCSSStreamResult = await Promise.allSettled(remoteCSSStreamPromise) console.log('remoteCSSStreamResult', remoteCSSStreamResult) const cssText = remoteCSSStreamResult.map((item) => { // @ts-ignore const { status, value } = item if (status === 'fulfilled') return value }) styles.forEach((css) => cssText.push(css.innerHTML)) return cssText } 通过 document.head.querySelectorAll('link[type="text/css"]') 获取所有外链 CSS; 通过 fetch 获取远程 CSS 流,结果为ReadableStream; 通过 handleCssStream 将可读流转换为 text 文本; 与其他 CSS 样式合并,最终转为文本内容,嵌入 html 内容中。 未解决的部分 表情无法导出,这个我看了下其他在线协作文档,也有同样的问题。 小结

其实,处理这些问题的方式也是很简单,因为html-docx-js是用html字符串来作为导出文档的输入。如果导出后发现样式不对的情况时,我们只需要去修改html内容即可。

如果有遇到像复选框checkbox这类不知道怎么解决的问题,也可以采用反推,先通过word转html,然后看转为html后的内容,再去修改需要导出的html内容,这也不失为一种解决问题的方式。

以上是我在使用html-docx-js插件时遇到的一些问题及处理方式,如果有遇到同样问题的小伙伴,可以说下你们的处理方式。或者这里没有提到的问题,也欢迎大家补充。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3