news 2026/4/19 12:42:35

wangEditor复制word公式转MathType格式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
wangEditor复制word公式转MathType格式

《长沙大二码农的暑假暴走开发记:Word图片转存功能の奇幻漂流》

Day1:需求诞生——从“懒癌晚期”到“技术狂魔”

“妈!我暑假要搞个大事!”
当我把“Word图片一键转存”的PPT甩在家庭群时,我妈回了个“?”,我爸回了句“6”。
其实动机很简单:作为学生会宣传部“专业P图师”(自封的),每次从Word里抠图都要经历:

  1. 右键另存为 → 弹出“此图片受保护”
  2. 截图 → 发现像素糊成马赛克
  3. 跪求原图 → 被设计师同学嘲讽“菜狗”

怒而拍桌“我要写个程序,让Word图片自动上传到服务器!”
(然后偷偷幻想:开学后能不能靠这个装逼接私活?)


Day2-3:组件狩猎——在GitHub的海洋里“捞鱼”

前端三件套

  • Vue2-cli:学校教过,勉强能用(反正复制粘贴代码不会错)
  • wangEditor:比CKEditor简单!但文档里“图片上传”部分写着“自行实现后端接口”……
    内心OS“所以爱会消失对吗?”
  • 免费解析库
    • mammoth.js:能提Word图片,但输出是Base64,上传会卡死浏览器(测试时直接让Chrome崩溃3次)
    • docx-preview:GitHub 1.8k星!但示例代码全是React的(作为Vue仔当场裂开)
    • pdf.js:处理PDF还行,但Word?“不,你不想”(强行适配后报错像放鞭炮)

最终妥协

  • 前端:用FileReader读Word文件 → 解析ZIP结构(毕竟docx本质是ZIP包)→ 手动捞word/media/下的图片
  • 后端:PHP接收图片流 → 存到阿里云OSS(参考了某位大佬的博客,代码抄得飞起)

QQ群交流
加入群223813913后,发现大佬们都在聊“K8s部署”“微服务”,而我:
“各位大佬,怎么用PHP把图片存到OSS啊?”
(群友:“建议重开”


Day4-7:开发实录——从“Hello World”到“Hello Bug”

Step1:前端搞事情

  • JSZip解压Word文件,结果发现:

    // 代码片段:捞图片的暴力写法constzip=newJSZip(file);constimages=[];zip.folder("word/media/").forEach((path,file)=>{if(/\.(png|jpg|jpeg)$/.test(path)){images.push(file.async("base64"));// 后来发现base64上传会炸}});

    Bug1word/media/可能不存在 → 加了个try-catch(优雅.jpg)
    Bug2:图片顺序乱套 → 改用Array.sort()按文件名排序(结果发现Word图片名是image1.pngimage10.png“微软你礼貌吗?”

  • 集成wangEditor上传:

    // 伪代码:把图片塞进编辑器consteditor=newwangEditor("#editor");editor.config.customUploadImg=async(files)=>{constformData=newFormData();formData.append("file",files[0]);// 实际要传所有图片…懒得改constres=awaitaxios.post("/upload",formData);editor.cmd.do("insertHTML",``);};

    Bug3:wangEditor的customUploadImg一次只能传一张图 → 改用Promise.all批量上传(手动狗头)

Step2:后端接盘

  • PHP接收图片流:
    // 极简版上传接口(实际有安全校验…大概)$file=$_FILES["file"];$oss=newOssClient($key,$secret,$endpoint);$oss->putObject("my-bucket",$file["name"],fopen($file["tmp_name"],"r"));echojson_encode(["url"=>"https://oss-cn-hangzhou.aliyuncs.com/my-bucket/".$file["name"]]);
    Bug4:文件名冲突 → 用uniqid()生成随机名(结果OSS里全是64a1b2c3d4e5f.png这种乱码)
    Bug5:MySQL存元数据时字段长度不够 → 把VARCHAR(255)改成TEXT“设计数据库时我在睡觉”

Step3:阿里云OSS配置

  • 创建Bucket → 设置跨域规则(CORS)→ 生成AccessKey(“千万别泄露!”
  • 测试时发现上传失败 → 查日志发现是**“签名错误”** → 原来是PHP SDK版本太旧…
    解决方案
    composerrequire aliyuncs/oss-sdk-php:^2.3# 升级到最新版

Day8-10:测试与部署——从“本地跑通”到“线上炸服”

本地测试

  • 用Word写了个测试文档,插了5张图(包括1张GIF动图)
  • 前端解析 → 上传 → 编辑器显示 →“成了!”(激动到打翻可乐)

部署到阿里云ECS

  • Nginx配置反向代理 → PHP-FPM跑后端 → MySQL存数据
  • 测试时发现:“上传大文件会超时!”
    解决方案
    • 修改php.ini
      upload_max_filesize = 50M post_max_size = 50M
    • Nginx加超时设置:
      client_max_body_size 50M; proxy_read_timeout 300s;

最终效果

  • 上传10MB的Word → 前端解析2秒 → 后端上传5秒 → 编辑器显示图片
  • “虽然慢,但至少能用了!”(老板感动到哭.jpg)

Day11:总结与装逼

技术栈回顾

  • 前端:Vue2 + wangEditor + JSZip
  • 后端:PHP + OSS SDK
  • 数据库:MySQL(存图片URL和元数据)
  • 服务器:阿里云ECS(学生机免费版)

群内装逼
“大佬们,我搞定了Word图片转存!虽然代码很烂…”
群友:“上GitHub!”
我:“算了,怕被喷…”(实际是懒)

未来计划

  1. 优化解析速度(用Web Worker)
  2. 支持Excel/PPT的图片提取(“先鸽着”
  3. 写个博客吹牛(“正在写…”

最后吐槽
“原来开发就是:‘抄代码 → 改Bug → 抄代码 → 改Bug’的无限循环…”
(但看到编辑器里显示的图片时,还是觉得…
“真香!”


(完)
P.S.:欢迎长沙的同行约饭交流!QQ群:223813913(群文件有源码,但**“慎用”**)

复制插件文件


安装jquery

npm install jquery

导入组件

importEfrom'wangeditor'const{$,BtnMenu,DropListMenu,PanelMenu,DropList,Panel,Tooltip}=Eimport{WordPaster}from'../../static/WordPaster/js/w'import{zyCapture}from'../../static/zyCapture/z'import{zyOffice}from'../../static/zyOffice/js/o'

初始化组件

//zyCapture ButtonclasszyCaptureBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){window.zyCapture.setEditor(this.editor).Capture();}tryChangeActive(){this.active()}}//zyOffice ButtonclassimportWordBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){window.zyOffice.SetEditor(this.editor).api.openDoc();}tryChangeActive(){this.active()}}//zyOffice ButtonclassexportWordBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){window.zyOffice.SetEditor(this.editor).api.exportWord();}tryChangeActive(){this.active()}}//zyOffice ButtonclassimportPdfBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){window.zyOffice.SetEditor(this.editor).api.openPdf();}tryChangeActive(){this.active()}}//WordPaster ButtonclassWordPasterBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).Paste();}tryChangeActive(){this.active()}}//wordImport ButtonclassWordImportBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importWord();}tryChangeActive(){this.active()}}//excelImport ButtonclassExcelImportBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importExcel();}tryChangeActive(){this.active()}}//ppt paster ButtonclassPPTImportBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importPPT();}tryChangeActive(){this.active()}}//pdf paster ButtonclassPDFImportBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor);WordPaster.getInstance().ImportPDF();}tryChangeActive(){this.active()}}//importWordToImg ButtonclassImportWordToImgBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importWordToImg();}tryChangeActive(){this.active()}}//network paster ButtonclassNetImportBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor);WordPaster.getInstance().UploadNetImg();}tryChangeActive(){this.active()}}exportdefault{name:'HelloWorld',data(){return{msg:'Welcome to Your Vue.js App'}},mounted(){vareditor=newE('#editor');WordPaster.getInstance({//上传接口:http://www.ncmem.com/doc/view.aspx?id=d88b60a2b0204af1ba62fa66288203edPostUrl:"http://localhost:8891/upload.aspx",License2:"",//为图片地址增加域名: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:''});zyCapture.getInstance({config:{PostUrl:"http://localhost:8891/upload.aspx",License2:'',FileFieldName:"file",Fields:{uname:"test"},ImageUrl:'http://localhost:8891{url}'}})// zyoffice,// 使用前请在服务端部署zyoffice,// http://www.ncmem.com/doc/view.aspx?id=82170058de824b5c86e2e666e5be319czyOffice.getInstance({word:'http://localhost:13710/zyoffice/word/convert',wordExport:'http://localhost:13710/zyoffice/word/export',pdf:'http://localhost:13710/zyoffice/pdf/upload'})// 注册菜单E.registerMenu("zyCaptureBtn",zyCaptureBtn)E.registerMenu("WordPasterBtn",WordPasterBtn)E.registerMenu("ImportWordToImgBtn",ImportWordToImgBtn)E.registerMenu("NetImportBtn",NetImportBtn)E.registerMenu("WordImportBtn",WordImportBtn)E.registerMenu("ExcelImportBtn",ExcelImportBtn)E.registerMenu("PPTImportBtn",PPTImportBtn)E.registerMenu("PDFImportBtn",PDFImportBtn)E.registerMenu("importWordBtn",importWordBtn)E.registerMenu("exportWordBtn",exportWordBtn)E.registerMenu("importPdfBtn",importPdfBtn)//挂载粘贴事件editor.txt.eventHooks.pasteEvents.length=0;editor.txt.eventHooks.pasteEvents.push(function(){WordPaster.getInstance().SetEditor(editor).Paste();e.preventDefault();});editor.create();varedt2=newE('#editor2');//挂载粘贴事件edt2.txt.eventHooks.pasteEvents.length=0;edt2.txt.eventHooks.pasteEvents.push(function(){WordPaster.getInstance().SetEditor(edt2).Paste();e.preventDefault();return;});edt2.create();}}h1,h2{font-weight:normal;}ul{list-style-type:none;padding:0;}li{display:inline-block;margin:010px;}a{color:#42b983;}

测试前请配置图片上传接口并测试成功
接口测试
接口返回JSON格式参考

为编辑器添加按钮

components:{Editor,Toolbar},data(){return{editor:null,html:'dd',toolbarConfig:{insertKeys:{index:0,keys:['zycapture','wordpaster','pptimport','pdfimport','netimg','importword','exportword','importpdf']}},editorConfig:{placeholder:''},mode:'default'// or 'simple'}},

整合效果

导入Word文档,支持doc,docx

导入Excel文档,支持xls,xlsx

粘贴Word

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

Word转图片

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

导入PDF

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

导入PPT

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

上传网络图片

一键自动上传网络图片,自动下载远程服务器图片,自动上传远程服务器图片

下载示例

点击下载完整示例

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

云服务器成本优化:从资源浪费到精细化管控的实践路径

云服务器成本优化&#xff1a;从资源浪费到精细化管控的实践路径某跨境电商的降本案例具有代表性&#xff1a;通过预留实例&#xff08;RI&#xff09;覆盖80%基础负载&#xff0c;结合按需实例应对流量波动&#xff0c;使AWS EC2成本下降42%&#xff1b;使用S3智能分层存储将归…

作者头像 李华
网站建设 2026/4/16 12:52:52

WebSocket总是断连?PHP开发者必须掌握的7种重连优化技巧

第一章&#xff1a;WebSocket断连问题的根源剖析WebSocket作为一种全双工通信协议&#xff0c;广泛应用于实时消息推送、在线协作等场景。然而在实际部署中&#xff0c;连接中断问题频繁发生&#xff0c;严重影响用户体验。深入分析其断连根源&#xff0c;是构建高可用性实时系…

作者头像 李华
网站建设 2026/4/18 10:00:59

Jenkins调用HeyGem API完成持续集成视频报告

Jenkins调用HeyGem API完成持续集成视频报告 在现代软件交付节奏日益加快的背景下&#xff0c;团队对“可见性”和“反馈速度”的要求已不满足于传统的日志输出或静态图表。一次构建是否成功&#xff1f;系统状态如何&#xff1f;这些问题如果能通过一段数字人播报的短视频直观…

作者头像 李华
网站建设 2026/4/17 15:17:31

露,步态分析系统 大鼠步态分析系统 小鼠步态分析系统

大小鼠步态即实验小鼠与大鼠行走过程中呈现的肢体姿态。大小鼠步态分析系统以传统足迹分析法为基础&#xff0c;足印图像增强技术&#xff0c;可清晰捕捉动物行走全程的足印信息&#xff1b;安徽&#xff0c;正华生物&#xff0c;露用于评估大小鼠步态和运动行为的设备&#xf…

作者头像 李华
网站建设 2026/4/17 20:31:01

基于AI与大数据的Python爬虫实战:深度解析招聘市场需求与技术趋势

一、引言&#xff1a;数据驱动时代的技能需求分析在当今数字化转型浪潮中&#xff0c;Python爬虫技术已成为数据获取与分析的核心技能。本文将通过构建一个智能化的招聘需求分析系统&#xff0c;深入挖掘市场对Python爬虫工程师的技能要求&#xff0c;展示如何运用最新技术栈实…

作者头像 李华
网站建设 2026/4/18 18:23:53

Python爬虫实战:运用Selenium与Asyncio技术深度挖掘投资机构持仓数据

引言&#xff1a;金融数据挖掘的价值与挑战在当今数字化金融时代&#xff0c;投资机构的持仓数据成为了市场参与者决策的重要参考依据。通过分析顶级投资机构的持仓变化&#xff0c;投资者可以洞察市场趋势、发现潜在投资机会。然而&#xff0c;这些宝贵数据分散在各个金融监管…

作者头像 李华