涿州网站建设,做网站内容都有哪些,广州市网站设计,手机网站宽度多少合适《苏州大二程序员的暑假“渡劫”日记#xff1a;Word图片转存样式保留大作战》 日期#xff1a;2023年7月18日 星期二 苏州 桑拿天#xff08;空调房里敲代码#xff0c;命是奶茶给的#xff09; 第一章#xff1a;需求暴击——客户爸爸的“变态”要求
“同学#xff0…《苏州大二程序员的暑假“渡劫”日记Word图片转存样式保留大作战》日期2023年7月18日 星期二 苏州 桑拿天空调房里敲代码命是奶茶给的第一章需求暴击——客户爸爸的“变态”要求“同学我们想实现个功能把Word里的图片和文字样式表格、字体、颜色全保留上传到服务器最后在网页编辑器里还能原样显示”我盯着微信对话框里的需求手里的冰奶茶差点捏爆——“这哪是需求这是让我用Vue2wangEditor5复刻一个在线版Word啊”但暑假闲着也是闲着不如趁机“渡劫”升级技能。Flag立下“7天内搞定否则直播倒立吃键盘”第二章组件狩猎——GitHub/Gitee“淘宝”记目标1提取Word内容保留样式mammoth.js能转Word为HTML但样式只支持部分比如字体加粗但表格边框可能丢。测试结果标题 数据1吐槽“这哪是保留样式这是‘样式随机丢弃’啊”docx-preview能预览Word但提取内容官方文档“本库只负责看不负责摸。”灵机一动“既然能预览那是不是能‘偷’它的渲染逻辑”结果预览是用Canvas画的根本拿不到DOM结构卒。pizzipdocxtemplater能解析Word的XML结构但需要手动处理样式。测试结果// 提取段落样式部分代码constparagraphsdoc.getJSON().sections[0].children;paragraphs.forEach(p{if(p.stylep.style.nameHeading1){console.log(这是标题,p.text);}});优点能拿到原始样式数据缺点需要自己写CSS映射比如把Word的“宋体 12pt 红色”转成CSS的font-family: SimSun; font-size: 12pt; color: red;。最终选择mammoth.js 手动补样式先保证功能再优化体验。目标2提取Word中的图片mammoth.js能提取图片但返回的是ArrayBuffer需要转Blob上传。代码片段constresultmammoth.extractRawText({arrayBuffer:wordArrayBuffer});result.images.forEach((image,index){constblobnewBlob([image.data],{type:image.contentType});// 上传Blob到服务器...});测试结果图片能上传但文件名是随机数“客户爸爸说图片得按‘文档名_序号’命名否则财务部阿姨找不到”。第三章前端攻坚——Vue2 wangEditor5的“魔改”之路Step 1让wangEditor5显示Word转换后的HTMLwangEditor5默认不支持直接插入HTML但可以“偷渡”// src/components/Editor.vueimport{Editor}fromwangeditor5import{Boot}fromwangeditor5/core// 自定义模块允许插入HTMLBoot.registerModule({name:htmlInsert,editor:Editor,config:(editor){editor.commands.addCommand(insertHTML,(html){constselectioneditor.getSelection()if(selection){editor.insertText( )// 先插入空格占位constrangeselection.getRange()constfragmenteditor.getModule(dom).createFragment(html)range.insertNode(fragment)}})}})// 使用示例consteditornewEditor({selector:#editor-container,config:{// 其他配置...}})editor.commands.execute(insertHTML,红色文字)测试结果简单样式颜色、加粗能显示复杂样式表格、嵌套列表会乱码“wangEditor5你管这叫HTML这是我从未见过的船新版本”。Step 2图片上传到阿里云OSS后端JSP签名前端上传逻辑// src/utils/ossUploader.jsexportasyncfunctionuploadToOSS(file,fileName){// 1. 请求JSP后端获取OSS签名constsignResponseawaitfetch(/api/oss-sign,{method:POST,body:JSON.stringify({fileName})});constsignDataawaitsignResponse.json();// 2. 直接上传到OSS无需经过自己服务器constformDatanewFormData();formData.append(key,signData.key);formData.append(policy,signData.policy);formData.append(OSSAccessKeyId,signData.accessId);formData.append(signature,signData.signature);formData.append(success_action_status,200);formData.append(file,file);constuploadResponseawaitfetch(signData.host,{method:POST,body:formData});returnuploadResponse.ok;}JSP后端简化版% page importjava.util.*, com.aliyun.oss.* % % // 生成OSS上传签名实际项目需加密处理 String accessKeyId your-access-key; String accessKeySecret your-secret-key; String endpoint oss-cn-suzhou.aliyuncs.com; String bucket your-bucket; // 生成POST上传策略 String policy {\expiration\:\2023-12-31T12:00:00.000Z\,\conditions\:[[\content-length-range\,0,104857600]]}; String base64Policy Base64.encodeBase64String(policy.getBytes()); String signature com.aliyun.oss.common.utils.BinaryUtil.toBase64String( com.aliyun.oss.common.auth.HmacSHA1Calculator.calculate( accessKeySecret.getBytes(), base64Policy.getBytes() ) ); // 返回签名给前端 out.print({\accessId\:\ accessKeyId \,\policy\:\ base64Policy \,\signature\:\ signature \,\host\:\https:// bucket . endpoint \}); %测试结果图片成功上传到OSSJSP代码被同学吐槽“像2005年的技术”“但Oracle数据库说它喜欢老古董”。第四章群友神助攻——QQ群里的“救星”在QQ群223813913里喊了一嗓子“求救wangEditor5怎么完美显示Word转换的HTML”群友北京-大佬“别用insertHTML用customPaste模块拦截粘贴事件手动解析HTML并转换样式”代码灵感// 自定义粘贴处理器editor.on(paste,(data){if(data.typetext/html){constparsernewDOMParser();constdocparser.parseFromString(data.data,text/html);// 手动处理表格样式consttablesdoc.querySelectorAll(table);tables.forEach(table{table.style.borderCollapsecollapse;table.style.width100%;// 遍历单元格添加边框...});// 替换编辑器内容editor.insertText();// 清空选中区域constrangeeditor.getSelection().getRange();constfragmenteditor.getModule(dom).createFragment(doc.body.innerHTML);range.insertNode(fragment);}});测试结果表格边框和颜色能显示了但嵌套列表还是乱“wangEditor5嵌套不存在的”。第五章客户爸爸的“真香”现场把测试链接发给客户后回复如下“这功能比我们之前用的在线文档还流畅明天请你喝‘秋天的第一杯奶茶’”内心OS**“苏州40度高温我需要的是冰可乐啊”**今日总结技术栈Vue2 wangEditor5 JSP Oracle 阿里云OSS关键点mammoth.js提取Word内容图片手动补CSS样式表格、字体、颜色JSP生成OSS签名虽然老但能用群友价值**“一个人调试BUG到凌晨不如群里喊一嗓子”**明日计划优化表格样式支持合并单元格写一篇技术博客《大二学生如何用Vue2JSP复刻Word在线编辑》签名苏州·在空调房里敲代码的大二狗2023年7月18日P.S.群里正在讨论“如何用Oracle存Word的样式数据”欢迎来交流“Oracle我虽然老但我能打”QQ群223813913暗号“Word转存”复制插件文件安装jquerynpm install jquery导入组件importEfromwangeditorconst{$,BtnMenu,DropListMenu,PanelMenu,DropList,Panel,Tooltip}Eimport{WordPaster}from../../static/WordPaster/js/wimport{zyCapture}from../../static/zyCapture/zimport{zyOffice}from../../static/zyOffice/js/o初始化组件//zyCapture ButtonclasszyCaptureBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-e-menu>)super($elem,editor)}clickHandler(){window.zyCapture.setEditor(this.editor).Capture();}tryChangeActive(){this.active()}}//zyOffice ButtonclassimportWordBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-e-menu>)super($elem,editor)}clickHandler(){window.zyOffice.SetEditor(this.editor).api.openDoc();}tryChangeActive(){this.active()}}//zyOffice ButtonclassexportWordBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-e-menu>)super($elem,editor)}clickHandler(){window.zyOffice.SetEditor(this.editor).api.exportWord();}tryChangeActive(){this.active()}}//zyOffice ButtonclassimportPdfBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-e-menu>)super($elem,editor)}clickHandler(){window.zyOffice.SetEditor(this.editor).api.openPdf();}tryChangeActive(){this.active()}}//WordPaster ButtonclassWordPasterBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-e-menu>)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).Paste();}tryChangeActive(){this.active()}}//wordImport ButtonclassWordImportBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-e-menu>)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importWord();}tryChangeActive(){this.active()}}//excelImport ButtonclassExcelImportBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-e-menu>)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importExcel();}tryChangeActive(){this.active()}}//ppt paster ButtonclassPPTImportBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-e-menu>)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importPPT();}tryChangeActive(){this.active()}}//pdf paster ButtonclassPDFImportBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-e-menu>)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor);WordPaster.getInstance().ImportPDF();}tryChangeActive(){this.active()}}//importWordToImg ButtonclassImportWordToImgBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-e-menu>)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importWordToImg();}tryChangeActive(){this.active()}}//network paster ButtonclassNetImportBtnextendsBtnMenu{constructor(editor){const$elemE.$(div classw-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(){vareditornewE(#editor);WordPaster.getInstance({//上传接口http://www.ncmem.com/doc/view.aspx?idd88b60a2b0204af1ba62fa66288203edPostUrl:http://localhost:8891/upload.aspx,License2:,//为图片地址增加域名http://www.ncmem.com/doc/view.aspx?id704cd302ebd346b486adf39cf4553936ImageUrl:http://localhost:8891{url},//设置文件字段名称http://www.ncmem.com/doc/view.aspx?idc3ad06c2ae31454cb418ceb2b8da7c45FileFieldName:file,//提取图片地址http://www.ncmem.com/doc/view.aspx?id07e3f323d22d4571ad213441ab8530d1ImageMatch:});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?id82170058de824b5c86e2e666e5be319czyOffice.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.length0;editor.txt.eventHooks.pasteEvents.push(function(){WordPaster.getInstance().SetEditor(editor).Paste();e.preventDefault();});editor.create();varedt2newE(#editor2);//挂载粘贴事件edt2.txt.eventHooks.pasteEvents.length0;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转换成图片上传到服务器中。上传网络图片一键自动上传网络图片自动下载远程服务器图片自动上传远程服务器图片下载示例点击下载完整示例