ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Vue2中wangEditor处理Word粘贴特殊格式的清洗与保真方案

Vue2中wangEditor处理Word粘贴特殊格式的清洗与保真方案 1. 项目里的老毛病Word表格公式一贴编辑器就“翻车”做Vue2老项目维护的兄弟应该都碰到过这种需求后台管理系统里放一个富文本编辑器要求用户从Word里把现成的文档内容复制粘贴进来然后保存到数据库再展示到页面。需求看起来只有一句话真做起来却能折腾掉半天——不是满屏的span style...抽风就是表格对不齐、图片变成了base64天书、公式直接变成乱码或消失。我最近在一个Vue2 Element UI的存量项目里复现并解决了这个问题用的编辑器是wangEditorVue2环境下的最佳选择之一v4版本轻量、无依赖、上手快。这篇不是来科普wangEditor的API而是专门聊一个场景在Vue2中用wangEditor处理从Word粘贴过来的特殊格式内容。适合遇到了同样问题的人参考也适合准备在Vue2老项目里接入wangEditor但害怕掉坑的朋友提前避雷。前后折腾了大概两周换过几种方案最终一套“从底层拦截粘贴、按需清洗、再做特殊结构保真”的组合拳把问题压下去了。今天把思路和代码都摊开讲能让你少走好几天弯路。2. 从Word复制出来的东西到底“脏”在哪2.1 剪贴板里的“HTML”并不是你以为的HTML先从最基本的说起。当你从Word里选中一段内容按下CtrlC再打开浏览器的DevTools在控制台执行document.addEventListener(paste, (e) { console.log(e.clipboardData.getData(text/html)); console.log(e.clipboardData.getData(text/plain)); });再把内容粘贴到任意文本域你会发现从Word复制出来的HTML和你平时手写的HTML完全是两个物种。Word的HTML里充斥着一大堆mso-style-parent:style0、mso-pagination:none这类Word私有样式!--[if gte mso 9]...![endif]--这种条件注释o:p/o:p、w:Sdt等临时标签和命名空间一堆内联的font-family、mso-前缀、line-height的px值表格用table嵌套宽高单位用磅pt间距用mso-padding-alt图片变成v:shape、v:imagedata或者base64内联代码公式要么是OMML数学对象要么直接一个“占位符”。如果直接把这段HTML扔进编辑器的innerHTML轻则页面样式被各种mso-污染重则整段内容被浏览器解析得面目全非。这是“特殊格式粘贴”问题的根源——不是wangEditor不好而是Word的HTML实在是太“特”了。2.2 wangEditor的默认粘贴能力不够用吗wangEditor v4的配置项里其实有几个和粘贴相关的开关pasteFilterStyle默认true会过滤掉Word的大部分内联样式pasteIgnoreImg默认false粘贴图片时是否忽略pasteText默认false设置为true时粘贴纯文本。实际测试下来pasteFilterStyle把它设置为true能过滤掉一大批Word私有样式但同时也把用户可能想要的字体、大小、颜色、对齐样式全部干掉了。设置成false表格的边框、宽度可能保留了但一堆mso-私有前缀又跑进编辑器内容里保存到数据库后在前端展示页面用v-html输出时同样会带出很多奇怪的东西。更重要的一个问题是wangEditor的默认粘贴处理对表格、列表、公式、图片这些“特殊结构”基本没有细化策略。复制过来的Word表格会被浏览器解析成HTML表格但列宽、边框样式常常丢公式要么整体消失要么退化成纯文字甚至变成一堆lt;m:oMathgt;。所以靠默认配置永远达不到“从Word复制进来到网页上效果接近原样”的期望。换句话说不是wangEditor不支持而是我们得自己接管“粘贴”这个行为在数据进编辑器之前做一次“安检”。3. 处理路径怎么选全清洗、纯文本、还是局部保真3.1 三种策略的适用场景在动手写代码前要先想明白需求到底要什么。因为“从Word粘贴特殊格式”这件事没有银弹只有取舍。第一种全清洗。无论Word带来的什么一律过滤成最基础的段落和换行。这种策略最安全适合公告、评论这类富文本要求不高的场景用户只需要贴文字样式不要。实现上取text/plain即可一行代码搞定但代价是用户从Word里辛苦排好的表格、字体、图片全没了。第二种纯HTML清洗。截获text/html用白名单方式删除所有非白名单标签和属性。适合多数后台管理场景——允许保留加粗、标题、列表、表格、链接但把Word私有样式全部剔除。这种策略兼顾了排版和风险控制也是我最终主要采用的方式。第三种局部保真。针对表格、图片、公式等特殊元素做定向提取和转码。比如说表格结构用干净的HTML模板重建图片转成服务器上传后的URL公式从OMML或MathML转成可识别的内容。这种策略效果最好但工程复杂度也最高需要做很多DOM解析和正则匹配。实际操作里我建议采用“2 3”的混合策略先用白名单清洗保住基础排版再对表格、图片、公式做特殊处理。纯文本策略可以作为“无样式粘贴”的备选功能比如工具栏上加一个“清除格式”按钮。3.2 技术选型自己写规则还是依赖工具库清洗HTML有很多现成方案比如xss.js、sanitize-html、DOMPurify。Vue2项目里原生用DOMPurify也很稳但wangEditor的HTML内容里包含一些自己的约定比如pbr/p、span stylebackground-color:...如果清洗规则过严反而把编辑器内部结构搞坏。我最终选择“原生DOM 自定义规则”来实现原因有两点项目依赖越少越好尤其老项目不想引入一堆npm包再和各种CSP策略缠斗自定义规则能够精准控制哪些标签和属性必须保留哪些专属于Word的私有前缀必须剔除表格和图片可以单独处理。这个选择完全够用而且逻辑透明。如果你图省事用DOMPurify也没问题但规则要仔细调后面我会给出一个适合wangEditor的清洗思路。4. 关键实现在Vue2 wangEditor里接管粘贴事件4.1 初始化编辑器并挂载到Vue2组件老规矩先展示一个最小可用的Vue2组件框架。wangEditor安装后在script里引入然后new E(...)创建实例。要注意的是wangEditor v4创建实例时既可以传CSS选择器也可以传DOM节点。在Vue2里推荐传ref获取真实DOM节点避免块级作用域下的选择器冲突。template div div refeditorBox classeditor-box/div input typefile acceptimage/* styledisplay:none reffileInput changehandleFileChange /div /template script import E from wangeditor; export default { name: RichEditor, data() { return { editor: null, }; }, mounted() { this.editor new E(this.$refs.editorBox); this.editor.config.height 400; this.editor.config.placeholder 请粘贴或输入内容...; // 先把wangEditor自带的过滤关掉完全交给自定义逻辑 this.editor.config.pasteFilterStyle false; this.editor.config.pasteIgnoreImg false; this.editor.config.zIndex 10; // 上传菜单做最小配置否则相关菜单不可用 this.editor.config.uploadImgShowBase64 true; this.editor.create(); // 接管粘贴事件 this.bindPasteHandler(); }, beforeDestroy() { // 注销事件避免组件销毁后回调还在 if (this.editor) { this.unbindPasteHandler(); this.editor.destroy(); } }, methods: { bindPasteHandler() { // 具体逻辑见下文 }, unbindPasteHandler() { // ... }, }, }; /script这里有几个坑值得提醒pasteFilterStyle必须设成false否则wangEditor会在你自定义处理之前就把样式过滤掉特别是有时候剪贴板里的HTML已经经过了Word的“隐式清洗”再被wangEditor的过滤器一搅局很多细节就无法恢复了。pasteIgnoreImg保持false因为后面我们要自己处理图片。在beforeDestroy里一定要调用this.editor.destroy()并移除事件监听。很多Vue2老项目的内存泄漏都出在这种全局事件/编辑器实例不及时清理的地方。4.2 拦截paste事件读取并清洗HTMLwangEditor没有暴露直接的“粘贴前处理”回调但它内部本质还是基于contenteditable的。所以最可靠的接管方式是拿到编辑器区域对应的DOM节点用原生addEventListener(paste, handler)去挂载事件。methods: { bindPasteHandler() { this._pasteHandler this.handlePaste.bind(this); // 关键wangEditor v4的text区域DOM是 editor.$textElem.ele this.editor.$textElem.ele.addEventListener(paste, this._pasteHandler); }, unbindPasteHandler() { if (this.editor.$textElem this.editor.$textElem.ele) { this.editor.$textElem.ele.removeEventListener(paste, this._pasteHandler); } }, handlePaste(e) { // 只处理HTML纯文本交给浏览器默认行为。但下面为了统一保留纯文本模式判断 const html e.clipboardData.getData(text/html); const text e.clipboardData.getData(text/plain); // 如果没有HTML内容直接当成纯文本插入避免“复制文本却变成HTML”的麻烦 if (!html) { e.preventDefault(); this.editor.cmd.do(insertHTML, this._escapeText(text)); return; } e.preventDefault(); const cleanedHtml this.cleanWordHtml(html); this.editor.cmd.do(insertHTML, cleanedHtml); }, _escapeText(text) { const div document.createElement(div); div.textContent text; return div.innerHTML; }, }需要注意editor.cmd.do(insertHTML, html)是wangEditor内部命令向下转发到浏览器的document.execCommand的。这样插入的内容会真正进入编辑器历史栈CtrlZ也能撤销不会出现“插进去但撤销不干净”的问题。4.3 清洗Word HTML的自定义规则接下来是重头戏cleanWordHtml。这是一整套基于DOM解析的清洗逻辑。核心思路是用DOMParser把HTML字符串解析成DOM树然后在树里做一次遍历洗涤最后序列化回字符串。methods: { cleanWordHtml(html) { const doc new DOMParser().parseFromString(html, text/html); // 1. 去掉Word条件注释以mso开头的内容 this.removeMsoComments(doc); // 2. 移除危险标签和Word私有命名空间元素 this.removeDangerAndNsElements(doc); // 3. 清除所有标签上的mso-属性和style前缀 this.cleanAttributes(doc); // 4. 重置表格为最简样式保留结构 this.normalizeTables(doc); // 5. 处理图片base64转占位/转上传逻辑 await this.handleImages(doc); // 6. 序列化返回 return doc.body.innerHTML; }, }这里要注意由于handleImages可能涉及异步上传cleanWordHtml需要变成async调用处也加await。我们先看前四步的明确实现。移除mso注释和私有标签removeMsoComments(doc) { // 遍历所有节点包括注释节点 const walker doc.createTreeWalker(doc.body, NodeFilter.SHOW_COMMENT); const comments []; while (walker.nextNode()) { comments.push(walker.currentNode); } comments.forEach((node) node.remove()); // 移除常见的Word私有标签 const privateTags [o:p, w:document, w:body, m:oMath, m:oMathPara, v:imagedata, v:shape, w:sdt]; privateTags.forEach((tag) { doc.body.querySelectorAll(tag).forEach((el) { const parent el.parentNode; while (el.firstChild) { parent.insertBefore(el.firstChild, el); } el.remove(); }); }); }NodeFilter.SHOW_COMMENT用来抓取!--[if gte mso 9]这类注释。亲测有效。注意遍历时要先收集再删除防止TreeWalker在删除节点后遍历指针崩溃。清除属性白名单之外的属性和样式大多数Word专用属性都在style属性内部也有直接以mso-开头的属性比如mso-height-source、mso-width-source。我的做法是遍历所有元素节点将style属性拆解成键值对只保留以下白名单text-align左、右、中、两端对齐font-weight加粗font-style斜体text-decoration下划线、删除线background-color高亮color字体颜色font-sizefont-family。其余全部删除。同时把class属性和>cleanAttributes(doc) { const allowedStyleKeys [ text-align, font-weight, font-style, text-decoration, background-color, color, font-size, font-family, ]; doc.body.querySelectorAll(*).forEach((el) { // 移除所有mso-开头的属性比如 mso-ignore mso-pagination Array.from(el.attributes).forEach((attr) { if (attr.name.startsWith(mso-) || attr.name.startsWith(data-)) { el.removeAttribute(attr.name); } if (attr.name class attr.value.includes(Mso)) { el.removeAttribute(attr.name); } }); // 重写style if (el.hasAttribute(style)) { const styleMap {}; el.getAttribute(style).split(;).forEach((item) { const [key, value] item.split(:).map((s) s.trim()); if (key value allowedStyleKeys.includes(key.toLowerCase())) { styleMap[key.toLowerCase()] value; } }); const newStyle Object.entries(styleMap) .map(([k, v]) ${k}: ${v}) .join(; ); if (newStyle) { el.setAttribute(style, newStyle); } else { el.removeAttribute(style); } } }); }注意font-size从Word粘贴出来经常是pt单位比如14pt。如果你希望页面显示效果接近Word保留这个单位没问题如果希望与项目CSS的风格一致建议把pt换算成px换算逻辑是1pt ≈ 1.333px。我通常会在cleanAttributes里顺手转一下if (key font-size value.endsWith(pt)) { const px parseFloat(value) * 1.333; styleMap[font-size] ${Math.round(px)}px; }这个细节虽然不复杂但实际体验明显不一样。很多用户从Word复制小四号字粘贴到页面上如果是pt显示器下字体偏小或偏大直接换成px视觉更统一。4.4 表格和列表从“Word结构”到“网页结构”的翻译Word表格粘贴后最常见的问题有两个一是列宽固定成Word里的绝对值经常是几百磅二是td的样式里带mso-border-alt之类的私有前缀。清洗完属性后表格还是那个表格但视觉效果经常崩。我的做法是让表格回归最简单的HTML结构然后让项目的CSS去管样式。具体的说遍历table移除宽高、边框只保留border1之类的HTML属性CSS样式任务交给样式表清除td、th上的所有宽度、高度、间隔样式如果td内部有多个换行合并成一个段落块对于嵌套表格只保留一层嵌套表格在Word文档里很常见但在网页展示往往乱套。normalizeTables(doc) { doc.body.querySelectorAll(table).forEach((table) { table.removeAttribute(width); table.removeAttribute(height); table.removeAttribute(style); table.setAttribute(border, 1); // 去除单元格样式 table.querySelectorAll(td, th).forEach((cell) { cell.removeAttribute(style); cell.removeAttribute(width); cell.removeAttribute(height); cell.removeAttribute(align); }); // 合并嵌套表格把子表格展开到父表格后面避免样式错乱 table.querySelectorAll(table).forEach((innerTable) { const row document.createElement(tr); const cell document.createElement(td); cell.appendChild(innerTable.cloneNode(true)); row.appendChild(cell); table.appendChild(row); innerTable.remove(); }); }); }列表的问题也类似。Word的列表可能使用p stylemso-list: l0 level1 lfo1但更常见的是纯文本加编号。我的建议是如果清洗后li结构存在保留ul/ol如果Word自带的结构已经被解析成段落加了数字序号比如1.、2.就保留为普通段落不要再强行转成列表。强行转换反而容易产生空li和换行符后期维护更痛苦。4.5 图片不要直接塞base64先转上传从Word复制粘贴图片剪贴板里通常有两种情况一是图片是真的图片clipboardData里会有resources或者files二是图片变成了v:shape加v:imagedata需要从Shape节点里提取链接。在wangEditor场景里最稳妥的是优先从clipboardData.files里拿图片文件上传到服务器后把返回的URL替换进HTML。但这是异步过程所以要把cleanWordHtml改成async然后在处理图片时调用一个handleImagesAsync。async handleImages(doc) { // 1. 处理v:shape / v:imagedata提取原始SRC const shapes doc.body.querySelectorAll(v\\:shape, v\\:imagedata, v\\:imagedata[src], v\\:imagedata[o:relid]); shapes.forEach((shape) { const src shape.getAttribute(src) || shape.getAttribute(o:href) || ; if (src) { const img document.createElement(img); img.src src; shape.replaceWith(img); } }); // 2. 处理base64图片 const base64Imgs Array.from(doc.body.querySelectorAll(img[src^data:image/])); for (const img of base64Imgs) { const base64 img.getAttribute(src); const file this.base64ToFile(base64); const url await this.uploadImage(file); // 这里替换成真实上传方法 if (url) { img.setAttribute(src, url); img.removeAttribute(style); // 清除Word带来的宽高间距 } } }我这里是“如果项目配置了uploadImgShowBase64 true先把base64转成File再上传”。base64ToFile的通用写法base64ToFile(dataUrl) { const arr dataUrl.split(,); const mime arr[0].match(/:(.*?);/)[1]; const bstr atob(arr[1]); let n bstr.length; const u8arr new Uint8Array(n); while (n--) u8arr[n] bstr.charCodeAt(n); return new File([u8arr], paste-${Date.now()}.png, { type: mime }); }如果后台只支持multipart/form-data上传直接FormData.append(file, file)就好。如果不想异步图省事也可以让wangEditor默认帮你把base64塞进内容里。但那样数据库体积会迅速膨胀前端展示时也会因为解码而卡顿。我强烈建议至少把超过50KB的图片转成线上URL。4.6 公式Word公式的“唯一出路”是图片Word里的公式可能是OMMLOffice Math Markup Language浏览器不会直接渲染。粘贴到ckeditor会有自带的数学公式处理wangEditor没有。热词里有“word公式转latex”“公式图片转word”说明这是刚需。实测下来从Word复制带有OMML公式的内容浏览器解析html后公式区域经常变成类似m:oMath m:fm:numm:rm:t1/m:t/m:r/m:num/m:f /m:oMath或者干脆变成一串方框乱码。wangEditor在这种格式下基本无解。我的处理策略分三种如果Word带的是公式占位图最常见就在前面removeMsoComments时尽量保留img然后用上面图片上传的逻辑处理如果内容是m:oMath应该在粘贴时检测到这类标签就把它整体替换为一个提示文本比如“【公式请使用编辑器公式功能插入】”并且做成一个带有样式的span classformula-placeholder方便用户后续手动处理更进阶一点可以尝试把OMML通过MathML转换工具转成MathML或LaTeX再渲染成图片。但这个工程成本高作为临时方案不值得。我自己更推荐第一种或第二种。removePrivateTags(doc) { // 如果存在m:oMath提取其中文本生成占位符 doc.body.querySelectorAll(m\\:oMath, m\\:oMathPara).forEach((node) { const placeholder document.createElement(span); placeholder.setAttribute(style, background-color: #f4f4f4; padding: 2px 6px; color: #666;); placeholder.textContent 【公式暂不可用请手动插入】; node.replaceWith(placeholder); }); }思路核心不让这些不被浏览器理解的内容以“半死状态”残留在编辑器里否则用户在后台看到一堆乱码保存后前台展示更乱。5. 一次完整的粘贴处理流水线把上面各个方法串起来完整的handlePaste长这样async handlePaste(e) { const html e.clipboardData.getData(text/html); const text e.clipboardData.getData(text/plain); if (!html) { e.preventDefault(); this.editor.cmd.do(insertHTML, this.escapeHtml(text)); return; } e.preventDefault(); const doc new DOMParser().parseFromString(html, text/html); // 1. 去掉Word条件注释 this.removeMsoComments(doc); // 2. 移除私有命名空间标签 公式占位 this.removePrivateTags(doc); // 3. 清洗属性白名单 this.cleanAttributes(doc); // 4. 表格规范化 this.normalizeTables(doc); // 5. 图片处理异步 await this.handleImages(doc); const cleanedHtml doc.body.innerHTML; // 6. 插入编辑器 this.editor.cmd.do(insertHTML, cleanedHtml); },如果觉得这样把所有粘贴内容都强行走一套流程太重也可以加白名单菜单比如提供“粘贴纯文本”按钮点击后直接把剪贴板里的text/plain用insertHTML插进去避免经过清洗逻辑。这在产品体验上是加分项。6. 实战排雷我踩过的那些坑以及彻底解决办法6.1 粘贴后整个编辑区内容被替换了有段时间我的代码居然把粘贴进来的内容替换掉编辑器全部内容而不是插入到光标处。排查后发现是this.editor.cmd.do(insertHTML, cleanedHtml)插错位置。原因是用户点击编辑器时没有把光标指向编辑区wangEditor的insertHTML命令是基于当前选区执行的如果选区不在编辑区内部就会插入到整个document末尾或者替换某些意外选区。解决办法是在粘贴事件触发前手动把光标设置到编辑器末尾或保留原位置。具体做法是handlePaste(e) { // 确保编辑器获得焦点 this.editor.$textElem.ele.focus(); // 然后让游标保持在当前位置再处理插入 // ... }但是直接focus()会把光标放到末尾导致用户粘贴位置不对。更好的是在编辑器创建后监听keyup和mouseup事件记录当前光标位置其实不用那么复杂。实践中只要用户是用鼠标点击了编辑器内容再粘贴浏览器默认选区就已经在编辑区。真正出问题的是用户从外部复制的过程中焦点并没有落在编辑器区域粘贴事件又恰好被编辑器区域的监听器捕获这时insertHTML会作用在可疑选区上。一个简单可靠的方案是在handlePaste里先判断document.activeElement是否在编辑器内部如果不是就重置一个选区到编辑器最后一个子节点末尾const editorEl this.editor.$textElem.ele; if (!editorEl.contains(document.activeElement)) { const range document.createRange(); range.selectNodeContents(editorEl); range.collapse(false); const sel window.getSelection(); sel.removeAllRanges(); sel.addRange(range); }这种方式把粘贴错位的概率降到最低。6.2 表格粘贴后列宽不受控Word表格的“干净”HTML不干净主要在于每个td都有一个数值型的width比如width: 74.6px删除style以后这些属性可能还在。我在normalizeTables里只删了style没删HTML属性结果表格还是被浏览器按固定宽度渲染。最终我把table和td/th的width、height属性也统统移除再在项目全局样式里写.editor-box table { width: 100%; border-collapse: collapse; } .editor-box td, .editor-box th { border: 1px solid #ccc; padding: 6px; }这样表格在页面上会自适应容器宽度不会因为Word里的几百pt值而撑破布局。6.3 粘贴base64图片后数据库和接口都超了这是一个真实事故。用户粘贴一个5MB的Word截图前端检测到base64塞进内容保存时接口直接414。我前面的方案提到要上传图片但还要加一个限制超过2 * 1024 * 1024约2MB的base64图片直接拒绝插入给出提示“图片过大请上传后再插入”。因为Word里的图片往往都是原图直接贴base64体积很吓人。还应该注意上传接口的同步性问题。如果你用async处理上传界面会发生短暂卡顿。建议在handlePaste时增加一个全局isPasting标志处理过程中用Loading遮罩防止用户重复粘贴。if (this.isPasting) { e.preventDefault(); return; } this.isPasting true; try { // ...处理粘贴逻辑 } finally { this.isPasting false; }6.4 公式和特殊符号乱码的兜底方案除了OMML还有一类“伪公式”——Word里其实是图片但使用扩展名.wmf或者.emf的矢量格式。浏览器对这两个格式是没法直接显示的。处理方法是在handleImages里如果遇到img.src以wmf或emf结尾直接把src清空替换成一个可编辑的板块if (img.src /\.(wmf|emf)$/i.test(img.src)) { img.outerHTML span classplaceholder-img[图片暂不支持请手动上传]/span; }不要试图用canvas绘制矢量格式解析成本高不值当。6.5 常见问题速查备忘问题现象处理方法样式丢失加粗、颜色、字体靠margin-left? 实际上是style过滤过严调整cleanAttributes白名单保留font-weight、color、text-align表格错位Word表格粘贴后宽高自相残杀在normalizeTables中强制移除宽高属性用CSS统一图片没显示粘贴时出现空白检查shape标签里的src是否为相对路径若无法访问则转为base64或上传公式乱码显示一堆m:oMath用占位符替换禁止保存脏HTML粘贴不生效点击后无反应或插入错位在handlePaste里重置选区到编辑器内部CtrlV没触发可能是wangEditor内部自带事件把默认paste屏蔽了改用paste事件绑定到editor.$textElem.ele并确保不要重复绑定7. 一点老项目经验谈这种需求在Vue2和wangEditor的组合里基本是绕不开的。我最后没有用满屏的正则去解析字符串而是用DOMParser把HTML先转成DOM再遍历处理原因很简单DOM操作比正则更可靠你可以精准定位到某个td、某个img不会出现正则把a标签误伤的情况。如果你手头正好是Vue2老项目不要一上来就考虑升级Vue3再换编辑器。老项目稳定为主这一个编辑器问题不值得升级重构。wangEditor v4的扩展性完全能支撑这些自定义逻辑只是需要你稍微静下心来梳理粘贴的数据流。另外强烈建议在项目里加一个“粘贴预览”或“粘贴内容日志”的调试工具在handlePaste里把原始HTML和清洗后的HTML都console.log出来。因为这个需求一次不可能调好用户的Word版本不同WPS、Office 2010/2016/365剪贴板HTML的结构天差地别没有日志很难复现线上报错。我每次处理完一位同事的实际文档都会顺手把脏HTML存个样例后面回归测试就有底了。如果你打算长期维护这个老系统还可以考虑把清洗规则抽成一个独立的pasteCleaner.js后续新页面直接复用不用每个编辑器组件里各自维护一套。我最后就是把这个方法抽成了工具模块组件里只留调用逻辑清爽很多。这套方案实测下来线上用户从Word粘贴一个十几页带表格、图片、段标题的文档整体效果能从原来的“惨不忍睹”变成“80%可接受”。剩下的20%比如复杂公式、浮动文本框、修订痕迹本质上已经超出富文本编辑器该管的范围倒不如早点引导用户截图贴图或者直接用文档预览组件处理。
返回列表