fix(document): 统一编辑器与文书纸的排版和字体口径

This commit is contained in:
yelan
2026-09-30 11:20:27 +08:00
parent 3628c5ed86
commit 1d271ef1bd
10 changed files with 268 additions and 63 deletions
+42 -17
View File
@@ -8,6 +8,10 @@
*
* 本模块只解除这些「布局锁定」,表格结构(行列、合并、边框、加粗、对齐)全部保留,
* 宽度改由各渲染端的 CSS 统一控制,避免同一份文书在不同容器里表现不一致。
*
* 解除动作本身是 `unlockTableLayout`,粘贴近来要用,**渲染出去也要用**:
* 编辑器序列化出来的表格自带 `style="width: auto"` 这类内联锁,只堵粘贴这一个口
* 挡不住它(详见该函数的注释)。
*/
const COMMENTS = /<!--[\s\S]*?-->/g
@@ -49,6 +53,43 @@ function sanitizeStyleAttribute(style: string): string {
.join('; ')
}
/**
* 解除表格上的「布局锁定」:绝对宽度、固定行高、固定布局、不换行、内容裁剪。
* 宽度交回渲染端 CSS(`.doc-paper table { width: 100% }` 那一套)。
*
* **两个边界都要做,少一个就会出现"编辑器里与渲染出来不一样"**:
*
* - **粘贴时**(本模块的 normalizePastedHtml):Word / WPS 的表格带 pt/px 绝对宽度、
* `nowrap` 与 `overflow: hidden`;
* - **渲染时**(utils/signing-document 的 buildSigningDocumentHtml):WangEditor 的表格
* 序列化会把宽度写成**内联样式** —— 它导出的每张表都是
* `<table style="width: auto;">`(见 @wangeditor/editor 的 table elemToHtml)。
* 而内联样式优先级高于 `.doc-paper table { width: 100% }`,于是同一张表
* 在编辑器里撑满版心(编辑器 DOM 上那个 width 是**属性**、值为 `auto` 时浏览器直接忽略),
* 到预览 / 签署就变成"按内容收缩",宽度两边对不上。渲染端统一按 CSS 排版才是唯一口径。
*
* 就地修改传入的文档片段,无返回值。
*/
export function unlockTableLayout(root: ParentNode): void {
root.querySelectorAll('table, col, colgroup, td, th').forEach((element) => {
LAYOUT_LOCK_ATTRIBUTES.forEach((name) => element.removeAttribute(name))
const style = element.getAttribute('style')
if (!style) {
return
}
const sanitized = sanitizeStyleAttribute(style)
if (sanitized) {
element.setAttribute('style', sanitized)
} else {
element.removeAttribute('style')
}
})
}
/**
* 归一化 Word / WPS 粘贴的富文本 HTML。
* 入参为空或解析失败时原样返回,不会抛错。
@@ -77,23 +118,7 @@ export function normalizePastedHtml(html: string): string {
})
// 表格、列定义与单元格:解除绝对尺寸与不换行约束,宽度交由渲染端 CSS 决定
root.querySelectorAll('table, col, colgroup, td, th').forEach((element) => {
LAYOUT_LOCK_ATTRIBUTES.forEach((name) => element.removeAttribute(name))
const style = element.getAttribute('style')
if (!style) {
return
}
const sanitized = sanitizeStyleAttribute(style)
if (sanitized) {
element.setAttribute('style', sanitized)
} else {
element.removeAttribute('style')
}
})
unlockTableLayout(root)
return root.innerHTML
}