這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
前言
我們公司目前在做基于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-dev npm install @types/html-docx-js @types/file-saver --dev
-
使用方法
參考官方示例
使用程序遇到的問題及處理方案
字體加粗不生效、字體背景顏色不生效處理
字體加粗<strong>和標記文本元素<mark>標簽需要替換為<b>和<span>標簽
const innerHtml = cloneEle.innerHTML // strong在word中不生效問題 .replace(/<strong>/g, '<b>') .replace(/<\/strong>/g, '</b>') // 背景色不生效問題 .replace(/<mark/g, '<span') .replace(/<\/mark>/g, '</span>')
h1 - h6 標題高度優化及未同步 word 檔案標題
我們檔案中的標題對應的 HTML 內容長這樣

需要將內容轉換為類似<h1>xxx</h1>這樣,不然 word 中編輯時不能對應標題,修改如下:
// 標題高度和字體失效 需要設定lineHeight和fontWeight
const 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<Element> = 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 的處理,首先考慮的是轉為<input type='checkbox' />來處理,結果轉完后并沒有顯示復選框;
接著又想著用 span 標簽生成一個方框,<span style='width: 16px;height: 16px...' />,這樣總能顯示了吧!結果依然不行,
正當我想不到辦法的時候,突然靈機一動,可不可以把 word 轉成 html 后看看 checkbox 最侄訓顯示成啥樣呢?
于是通過在線 word 轉 html將 word 轉為 html 后,看到復選框對應的 html 內容為<span style="color:#333333; font-family:'Wingdings 2'; font-size:11pt">?</span>,改一下吧,
const span = document.createElement('span')
span.innerHTML = `<span style="color:#333333; font-family:'Wingdings 2'; font-size:11pt">?</span>`
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 = https://www.cnblogs.com/smileZAZ/archive/2023/04/10/`${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
如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/549692.html
標籤:其他

