最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

世界速看:记录-html-docs-js避坑指南

来源:博客园

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

前言

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

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


(资料图)

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

使用说明

  • 安装

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

npm install html-docx-js-typescript file-saver --save-devnpm install @types/html-docx-js @types/file-saver --dev
  • 使用方法

    参考官方示例

使用过程遇到的问题及处理方案

字体加粗不生效、字体背景颜色不生效处理

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

const innerHtml = cloneEle.innerHTML  // strong在word中不生效问题  .replace(//g, "")  .replace(/<\/strong>/g, "")  // 背景色不生效问题  .replace(//g, "")

h1 - h6 标题高度优化及未同步 word 文档标题

我们文档中的标题对应的 HTML 内容长这样

需要将内容转换为类似

xxx

这样,不然 word 中编辑时不能对应标题,修改如下:

// 标题高度和字体失效 需要设置lineHeight和fontWeightconst handleLevelStyle = (cloneEle: HTMLElement) => {  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 的 APIinsertAdjacentElement。

在 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 内容

参考了一下钉钉文档

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

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)})

未解决的部分

  • 表情无法导出,这个我看了下其他在线协作文档,也有同样的问题。

小结

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

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

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

本文转载于:

https://juejin.cn/post/7220244579671916604

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

关键词: