|
- /**
- * 后台富文本清洗(协议、公告等静态内容)
- *
- * 背景:html 表里的正文是 Word / 旧编辑器导出的,存在两类问题会破坏移动端排版:
- * 1. 大量 `<p><span> </span></p>` 空段落,叠加段间距后出现大片空白;
- * 2. 几乎每个 span 都带内联 `font-family:宋体;font-size:14px;color:#000`,
- * 内联样式优先级最高,会盖掉端上给的 tagStyle,导致字号偏小、暗色模式不可读。
- *
- * 处理方式:删掉空段落,剥掉会影响排版与主题的内联属性,保留加粗、下划线等语义样式。
- */
-
- // 会破坏排版 / 主题的内联属性,统一剥掉,交给端上的 tagStyle 决定
- const DROP_STYLE_PROPS = [
- 'font-family',
- 'font-size',
- 'color',
- 'background',
- 'background-color',
- 'line-height',
- 'margin',
- 'margin-top',
- 'margin-bottom',
- 'margin-left',
- 'margin-right',
- 'padding',
- 'padding-top',
- 'padding-bottom',
- 'width',
- 'height'
- ]
-
- /** 判断一段 html 是否只有空白内容(空格、 、<br>、空标签) */
- function isBlankFragment(html) {
- const text = String(html || '')
- .replace(/<br\s*\/?>/gi, '')
- .replace(/<[^>]+>/g, '')
- .replace(/ | |\u00a0/gi, '')
- .replace(/\s/g, '')
- return text.length === 0
- }
-
- /** 过滤单个 style 属性里的危险声明 */
- function cleanStyleValue(style) {
- return String(style || '')
- .split(';')
- .map((item) => item.trim())
- .filter(Boolean)
- .filter((item) => {
- const prop = item.split(':')[0].trim().toLowerCase()
- return prop && !DROP_STYLE_PROPS.includes(prop)
- })
- .join('; ')
- }
-
- /**
- * @param {string} html 后台返回的富文本
- * @return {string} 清洗后的富文本
- */
- export function cleanRichText(html) {
- if (!html) return ''
- let text = String(html)
-
- // 1. Word 导出常见的无用标签
- text = text
- .replace(/<\/?o:p[^>]*>/gi, '')
- .replace(/<!--[\s\S]*?-->/g, '')
- .replace(/<meta[^>]*>/gi, '')
- .replace(/<style[\s\S]*?<\/style>/gi, '')
-
- // 2. 剥掉内联的字体/颜色/间距声明,style 清空后连属性一起去掉
- text = text.replace(/\sstyle\s*=\s*"([^"]*)"/gi, (match, style) => {
- const kept = cleanStyleValue(style)
- return kept ? ` style="${kept}"` : ''
- })
- text = text.replace(/\sstyle\s*=\s*'([^']*)'/gi, (match, style) => {
- const kept = cleanStyleValue(style)
- return kept ? ` style="${kept}"` : ''
- })
-
- // 3. Word 会把字体信息塞进 font 标签和 class,一并清掉
- text = text.replace(/<\/?font[^>]*>/gi, '')
- text = text.replace(/\sclass\s*=\s*"(?:Mso|xl)[^"]*"/gi, '')
-
- // 4. 删掉只剩空白的段落 / 标题(连续空段落是大片空白的主因)
- text = text.replace(/<(p|div|h[1-6])\b[^>]*>([\s\S]*?)<\/\1>/gi, (match, tag, inner) => {
- return isBlankFragment(inner) ? '' : match
- })
-
- // 5. 连续 <br> 压缩为一个,避免用 br 堆出的空行
- text = text.replace(/(?:<br\s*\/?>\s*){2,}/gi, '<br>')
-
- return text.trim()
- }
-
- export default cleanRichText
|