news 2026/5/1 7:47:50

教育平台TinyMCE4处理Word艺术字粘贴变成乱码如何修复?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
教育平台TinyMCE4处理Word艺术字粘贴变成乱码如何修复?

作为陕西某软件公司的一名前端工程师,近期我接到了一个关键需求:需在企业网站的后台管理系统文章发布模块中,集成Word粘贴、Word文档导入及微信公众号内容粘贴(含自动下载并上传公众号文章图片至服务器)的功能。这一需求旨在通过Web编辑器工具栏新增插件实现,要求集成便捷、不影响现有系统功能,且用户操作需简单直观。以下是我从需求分析、产品评估到开发实现的全过程记录。


一、需求分析与产品评估

需求梳理

  1. Word粘贴功能:支持从Word复制内容并粘贴至编辑器,图片自动上传至服务器(初期本地存储,后期迁移至阿里云/华为云OBS/腾讯云等对象存储),保留文档样式(表格、字体、颜色等)。
  2. 微信公众号内容粘贴:自动解析公众号文章中的图片并上传至服务器,避免使用BASE64编码(因质量低且增加HTML体积)。
  3. 文档导入功能:支持Word、Excel、PPT、PDF导入,保留图片和样式。
  4. 技术约束:前端基于vue2-cli + TinyMCE,后端SpringBoot,开发工具IntelliJ IDEA,数据库MySQL,服务器阿里云。

产品评估

  • TinyMCE插件生态:TinyMCE虽有官方paste插件,但无法满足图片自动上传和样式保留需求,需定制开发。
  • 第三方库对比
    • Mammoth.js:适合Word文档解析,但需扩展图片上传逻辑。
    • Docx.js/PDF.js:分别用于Word/PDF解析,但集成复杂度高。
    • 自定义解决方案:结合TinyMCE API和后端服务,实现灵活控制。

结论:采用自定义开发方案,基于TinyMCE扩展插件,结合后端SpringBoot服务处理图片上传和文档解析。


二、开发过程

1. 前端插件开发(TinyMCE扩展)

步骤

  1. 注册插件:在TinyMCE初始化配置中添加自定义插件。
  2. 监听粘贴事件:拦截粘贴内容,提取图片和HTML。
  3. 图片上传:通过FormData将图片二进制数据发送至后端。
  4. 样式保留:使用cleanHtml方法过滤冗余标签,保留核心样式。

代码示例(前端插件核心逻辑)

// plugins/customPaste/plugin.jstinymce.PluginManager.add('customPaste',function(editor){editor.on('paste',function(e){constclipboardData=e.clipboardData||window.clipboardData;constitems=clipboardData.items;// 处理图片上传for(leti=0;i<items.length;i++){if(items[i].type.indexOf('image')!==-1){constfile=items[i].getAsFile();uploadImage(file).then(url=>{// 替换图片URL为服务器地址consthtml=editor.getContent({format:'html'});editor.setContent(html.replace(/src="data:image\/[^;]+;base64,/g,`src="${url}`));});}}// 保留Word样式(简化版)consthtml=clipboardData.getData('text/html');constcleanedHtml=cleanWordHtml(html);// 自定义方法过滤冗余标签editor.insertContent(cleanedHtml);});functionuploadImage(file){constformData=newFormData();formData.append('file',file);returnfetch('/api/upload',{method:'POST',body:formData}).then(res=>res.json()).then(data=>data.url);}});
2. 后端服务开发(SpringBoot)

功能

  1. 图片上传接口:接收二进制文件,存储至本地或对象存储(如阿里云OSS)。
  2. 文档解析接口:调用Mammoth.js/Apache POI解析Word/Excel,返回HTML和图片列表。

代码示例(图片上传接口)

// Controller层@RestController@RequestMapping("/api")publicclassFileUploadController{@PostMapping("/upload")publicResponseEntity>uploadFile(@RequestParam("file")MultipartFilefile){try{// 保存至本地(示例)StringfilePath="/uploads/"+UUID.randomUUID()+".png";file.transferTo(newFile(filePath));// 返回URL(实际项目需替换为对象存储URL)Mapresponse=newHashMap<>();response.put("url","https://your-domain.com"+filePath);returnResponseEntity.ok(response);}catch(Exceptione){returnResponseEntity.status(500).build();}}}

文档解析示例(使用Mammoth.js)

// 服务层(简化版)publicStringconvertDocxToHtml(MultipartFilefile)throwsIOException{ByteArrayInputStreamstream=newByteArrayInputStream(file.getBytes());Mammoth.Resultresult=Mammoth.convertToHtml(stream);returnresult.getValue();// 返回HTML字符串}
3. 集成与测试
  1. TinyMCE配置:在vue2-cli项目中注册插件。
// main.jsimport'tinymce/plugins/customPaste';// 引入自定义插件Vue.prototype.$tinymce.init({selector:'#editor',plugins:'customPaste',// 启用插件toolbar:'customPasteButton',// 添加工具栏按钮});
  1. 功能测试
    • 验证Word粘贴是否保留样式和图片。
    • 检查微信公众号图片是否自动上传。
    • 测试多格式文档导入(Word/PDF等)。

三、总结与优化

  1. 性能优化

    • 图片上传采用异步队列,避免阻塞主线程。
    • 对大文件分片上传,提升稳定性。
  2. 扩展性

    • 抽象图片存储层,支持多云厂商切换。
    • 文档解析服务独立部署,减轻主应用负载。
  3. 安全性

    • 限制上传文件类型和大小。
    • 对用户输入进行XSS过滤。

通过此次开发,我们成功实现了客户需求,且代码结构清晰,便于后期维护和扩展。

复制插件

安装jquery

npm install jquery

在组件中引入

// 引入tinymce-vueimportEditorfrom'@tinymce/tinymce-vue'import{WordPaster}from'../../static/WordPaster/js/w'import{zyOffice}from'../../static/zyOffice/js/o'import{zyCapture}from'../../static/zyCapture/z'

添加工具栏

//添加导入excel工具栏按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor).importExcel()}varregister$1=function(editor){editor.ui.registry.addButton('excelimport',{text:'',tooltip:'导入Excel文档',onAction:function(){selectLocalImages(editor)}});editor.ui.registry.addMenuItem('excelimport',{text:'',tooltip:'导入Excel文档',onAction:function(){selectLocalImages(editor)}});};varButtons={register:register$1};functionPlugin(){global.add('excelimport',function(editor){Buttons.register(editor);});}Plugin();}());//添加word转图片工具栏按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor);WordPaster.getInstance().importWordToImg()}varregister$1=function(editor){editor.ui.registry.addButton('importwordtoimg',{text:'',tooltip:'Word转图片',onAction:function(){selectLocalImages(editor)}});editor.ui.registry.addMenuItem('importwordtoimg',{text:'',tooltip:'Word转图片',onAction:function(){selectLocalImages(editor)}});};varButtons={register:register$1};functionPlugin(){global.add('importwordtoimg',function(editor){Buttons.register(editor);});}Plugin();}());//添加粘贴网络图片工具栏按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor);WordPaster.getInstance().UploadNetImg()}varregister$1=function(editor){editor.ui.registry.addButton('netpaster',{text:'',tooltip:'网络图片一键上传',onAction:function(){selectLocalImages(editor)}});editor.ui.registry.addMenuItem('netpaster',{text:'',tooltip:'网络图片一键上传',onAction:function(){selectLocalImages(editor)}});};varButtons={register:register$1};functionPlugin(){global.add('netpaster',function(editor){Buttons.register(editor);});}Plugin();}());//添加导入PDF按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor);WordPaster.getInstance().ImportPDF()}varregister$1=function(editor){editor.ui.registry.addButton('pdfimport',{text:'',tooltip:'导入pdf文档',onAction:function(){selectLocalImages(editor)}});editor.ui.registry.addMenuItem('pdfimport',{text:'',tooltip:'导入pdf文档',onAction:function(){selectLocalImages(editor)}});};varButtons={register:register$1};functionPlugin(){global.add('pdfimport',function(editor){Buttons.register(editor);});}Plugin();}());//添加导入PPT按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor);WordPaster.getInstance().importPPT()}varregister$1=function(editor){editor.ui.registry.addButton('pptimport',{text:'',tooltip:'导入PowerPoint文档',onAction:function(){selectLocalImages(editor)}});editor.ui.registry.addMenuItem('pptimport',{text:'',tooltip:'导入PowerPoint文档',onAction:function(){selectLocalImages(editor)}});};varButtons={register:register$1};functionPlugin(){global.add('pptimport',function(editor){Buttons.register(editor);});}Plugin();}());//添加导入WORD按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor).importWord()}varregister$1=function(editor){editor.ui.registry.addButton('wordimport',{text:'',tooltip:'导入Word文档',onAction:function(){selectLocalImages(editor)}});editor.ui.registry.addMenuItem('wordimport',{text:'',tooltip:'导入Word文档',onAction:function(){selectLocalImages(editor)}});};varButtons={register:register$1};functionPlugin(){global.add('wordimport',function(editor){Buttons.register(editor);});}Plugin();}());//添加WORD粘贴按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');varico="http://localhost:8080/static/WordPaster/plugin/word.png"functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor).PasteManual()}varregister$1=function(editor){editor.ui.registry.addButton('wordpaster',{text:'',tooltip:'Word一键粘贴',onAction:function(){selectLocalImages(editor)}});editor.ui.registry.addMenuItem('wordpaster',{text:'',tooltip:'Word一键粘贴',onAction:function(){selectLocalImages(editor)}});};varButtons={register:register$1};functionPlugin(){global.add('wordpaster',function(editor){Buttons.register(editor);});}Plugin();}());

在线代码:

添加插件

// 插件plugins:{type:[String,Array],// default: 'advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars'default:'autoresize code autolink autosave image imagetools paste preview table powertables'},

点击查看在线代码

初始化组件

// 初始化WordPaster.getInstance({// 上传接口:http://www.ncmem.com/doc/view.aspx?id=d88b60a2b0204af1ba62fa66288203edPostUrl:'http://localhost:8891/upload.aspx',// 为图片地址增加域名:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936ImageUrl:'http://localhost:8891{url}',// 设置文件字段名称:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45FileFieldName:'file',// 提取图片地址:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1ImageMatch:''})

在页面中引入组件

功能演示

编辑器

在编辑器中增加功能按钮

导入Word文档,支持doc,docx

导入Excel文档,支持xls,xlsx

粘贴Word

一键粘贴Word内容,自动上传Word中的图片,保留文字样式。

Word转图片

一键导入Word文件,并将Word文件转换成图片上传到服务器中。

导入PDF

一键导入PDF文件,并将PDF转换成图片上传到服务器中。

导入PPT

一键导入PPT文件,并将PPT转换成图片上传到服务器中。

上传网络图片

一键自动上传网络图片。

下载示例

点击下载完整示例

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/27 10:09:20

Secretin (human) ;HSDGTFTSERLSRLEGGARLQRLGQGLV-NH₂

一、基础信息 英文名称&#xff1a;Secretin (human)三字母序列&#xff1a;His-Ser-Asp-Gly-Thr-Phe-Thr-Ser-Glu-Leu-Ser-Arg-Leu-Arg-Glu-Gly-Ala-Arg-Leu-Gln-Arg-Leu-Leu-Gln-Gly-Leu-Val-NH₂单字母序列&#xff1a;HSDGTFTSERLSRLEGGARLQRLGQGLV-NH₂关键特征&#xff…

作者头像 李华
网站建设 2026/4/19 6:36:28

探索六轴EtherCAT总线伺服涂布收卷机程序的奇妙世界

六轴EtherCAT总线伺服涂布收卷机程序&#xff0c;采用六个伺服变频器编码器&#xff0c;动态测量频率&#xff0c;计算转速&#xff0c;再换算频率&#xff0c;用变频器同步伺服电机速度&#xff0c;进行通讯控制&#xff0c;具备一定参考价值。 在自动化控制领域&#xff0c;六…

作者头像 李华
网站建设 2026/4/15 15:32:43

*终端渲染天花板:isoneback小函数诞生记——ai终端渲染状态机设定编码序列re解析复杂实现催生我的简洁创造

智能复杂惹不甘&#xff0c;搜肠刮肚终成篇。 笔记模板由python脚本于2026-02-04 11:42:16创建&#xff0c;本篇笔记适合不满代码表达繁复的coder翻阅。 学习的细节是欢悦的历程 博客的核心价值&#xff1a;在于输出思考与经验&#xff0c;而不仅仅是知识的简单复述。 Python官…

作者头像 李华
网站建设 2026/4/18 21:45:04

【技术管理的第一次转身】从问题感知到方案落地

高效能人士与普通人的核心差异&#xff0c;往往不在于解决问题的能力&#xff0c;而在于发现、定义和系统化分析问题的能力。一、问题意识&#xff1a;一切改进的起点 解决问题的第一步&#xff0c;是意识到问题的存在。培养敏锐的“问题意识”&#xff0c;是提升个人与团队效能…

作者头像 李华
网站建设 2026/4/29 8:24:19

西门子PLC博途:三种自动流程程序写法大揭秘

西门子PLC博途3种自动流程程序写法 本案例介绍3种不同的方法去写自动流程程序。 第一种是用scl case语录&#xff0c;另外的两种使用梯形图的模式去写。 使用此类方法去写&#xff0c;清晰明了&#xff0c;非常使用。 并且针对程序配有视频解说&#xff0c;轻松上手 在西门子P…

作者头像 李华
网站建设 2026/5/1 4:42:33

Win11 临时文件清理实战

目录 一、什么是 Win11 的“临时文件”&#xff1f;为什么会越积越多&#xff1f; 二、方法一&#xff1a;使用 Win11 官方推荐的「存储感知」清理&#xff08;新手首选&#xff09; 操作步骤 常见可勾选项说明&#xff08;重点&#xff09; 清理效果 三、方法二&#xff…

作者头像 李华