2026/4/7 18:28:42
网站建设
项目流程
可以做彩页的网站,网络营销和网络推广,电子平台网站建设,seo全网营销前言
这两天在做一个在线预览各种类型文档的模块#xff0c;主要是针对pdf和word#xff0c;pdf好说#xff0c;方案一大把#xff0c;选一个最合适的就好#xff0c;我这里的管理项目是基于MudBlazor的#xff0c;所以我使用了官方推荐的Pdf扩展组件Gotho.BlazorPdf主要是针对pdf和wordpdf好说方案一大把选一个最合适的就好我这里的管理项目是基于MudBlazor的所以我使用了官方推荐的Pdf扩展组件Gotho.BlazorPdf当然即便不用原生组件自己基于pdf.js等前端方案来封装也是完全没问题的这个我就不多说了。这里主要想聊聊在线预览word文档的实现思路总结起来基本就是3条路线第一条是先把word格式转成pdf然后再通过pdf预览组件来预览这条路线实现方案也很多问题就是装换的实现如果你之前没有写过类似的功能可能要费一番功夫当然不差钱的话可以用一些商用组件比如Aspose Spire.Doc等虽然价格略高但专业性高功能极强物有所值。当然除了转化成pdf还可以转换成html或者markdown等总之就是转换的路线这里不再赘述。第二条路线是借助微软原生的 Office Online 服务或者Google Viewer等方案实现在线预览当然这也有一个要求就是你的文档需要能在公网访问或者有运维能力的话可以在本地部署一个私有Office Online服务这个微软官方有详细的文档https://learn.microsoft.com/zh-cn/officeonlineserver/deploy-office-online-server对这种方式感兴趣的小伙伴可以试试笔者不推荐私有部署的方式如果你的场景里文档允许外网访问的话推荐直接使用在线方式最简单。第三条路线是使用一些纯前端方案更加的轻量级当然他会有一些限制条件比如一些表现好的组件不支持原始的doc格式只能是docx超过10M的渲染可能也会很慢。所以选型时要考虑这些条件笔者采用的就是这条路线。方案介绍近几年前端发展迅猛在线预览复杂的word文档已经有了成熟方案比如mammoth.jsdocx-preview.jsamis.js等这里面mammoth还提供了.net的nuget包方便Blazor环境使用但有个问题是他渲染出来的文档会影响原文布局所以如果只是“看内容”不在乎排版受影响那.net环境下使用前端方案实现文档预览mammoth毫无疑问是最佳方案。但我这里是一个“审核”的场景需要对源文件实现“公文级”设置“像素级”的还原也就是和word文档几乎一样所以更适合我这里的方案是“docx-preview.js”仓库地址https://github.com/VolodymyrBaydalka/docxjs。至于另外一个amis.js这个是国内大厂百度出品的一个组件文档很全也是一个不错的路线。实现步骤引入组件因为是客户端方案我们可以在外边通过npm等方式先把核心组件拉到本地当然直接在VS里添加客户端库也可以。npminstalldocx-preview编写隔离型 JS 互操作层在 wwwroot/assets/js/docxInterop.js 中我们不仅要处理预览逻辑还要处理环境隔离。/** * 我这里因为用到了Monaco Editor组件因此要处理一下AMD加载器的冲突 */exportasyncfunctionrenderDocxFromUrl(url,containerId){constcontainerdocument.getElementById(containerId);if(!container)return;constloadScriptWithIsolation(src){returnnewPromise((resolve,reject){if(document.querySelector(script[src${src}])){resolve();return;}// 临时屏蔽全局define函数防止与Monaco Editor等库的AMD加载器冲突const_backupDefinewindow.define;window.defineundefined;constscriptdocument.createElement(script);script.srcsrc;script.onload(){window.define_backupDefine;// 加载后立即还原resolve();};script.onerrorreject;document.head.appendChild(script);});};try{// 1. 加载依赖awaitloadScriptWithIsolation(./assets/js/jszip.min.js);awaitloadScriptWithIsolation(./assets/js/docx-preview.min.js);// 2. 获取文件流constresponseawaitfetch(url);constarrayBufferawaitresponse.arrayBuffer();// 3. 调用预览逻辑constoptions{className:docx-preview,inWrapper:true,breakPages:true};awaitwindow.docx.renderAsync(arrayBuffer,container,null,options);}catch(e){console.error(预览失败:,e);container.innerHTML文档加载失败;}}封装 Blazor 预览组件使用 IJSObjectReference 确保 JS 逻辑的模块化避免污染全局命名空间。inject IJSRuntime JS implements IAsyncDisposabledivid_containerIdclassdocx-render-areastyleheight:Height; overflow:auto;/divcode{[Parameter]publicstringHeight{get;set;}700px;privatestring_containerId$docx-{Guid.NewGuid():N};// JS 模块引用privateIJSObjectReference?_module;protectedoverrideasyncTaskOnAfterRenderAsync(boolfirstRender){if(firstRender){// 动态加载 JS 模块文件_moduleawaitJS.InvokeAsyncIJSObjectReference(import,/assets/js/docxInterop.js);}}publicasyncTaskLoadFromUrlAsync(stringurl){if(_modulenull)return;try{//_isLoading true;StateHasChanged();// 直接把 URL 传给 JS 处理避免大数组在 SignalR 中传输await_module.InvokeVoidAsync(renderDocxFromUrl,url,_containerId);}finally{//_isLoading false;StateHasChanged();}}publicasyncTaskLoadFromStreamAsync(Streamstream){if(_modulenull)return;usingvarmsnewMemoryStream();awaitstream.CopyToAsync(ms);await_module.InvokeVoidAsync(renderDocx,ms.ToArray(),_containerId);}// 释放模块引用防止内存泄漏publicasyncValueTaskDisposeAsync(){if(_module!null){try{// 只有当连接还活着的时候才去调用 Disposeawait_module.DisposeAsync();}catch(JSDisconnectedException){// 忽略连接断开导致的异常这是正常的}}}}父组件引入父组件的引入的时候只要给一个高度参数就可以了// blazor页面部分引入组件DocxViewerref_docxViewerHeight75vh/// code部分编写引入逻辑privateDocxViewer_docxViewer;privateasyncTaskLoadFile(stringurl){if(_docxViewer!null)await_docxViewer.LoadFromUrlAsync(url);}最后的效果如下服务器配置在服务注入的入口中适当调高 SignalR 的传输上限这个仅限Blazor Server模式BlazerWSAM或者Hybird方式不需要builder.Services.AddServerSideBlazor().AddHubOptions(options{options.MaximumReceiveMessageSize32*1024*1024;// 32MB});* 避坑我在集成过程中遇到了类似“Uncaught Error: Can only have one anonymous define call”的报错。排查后的原因是使用了Monaco Editor这样的库自带了 AMD 加载器loader.js。docx-preview 检测到define函数后会尝试注册模块导致冲突。解决方案采用动态加载脚本并在加载期间暂时“抹除”全局define。总结通过这种方式不仅在 Blazor Server 中实现了 Word 文档的高保真预览而且足够轻量化还可以方便的将其用到任何需要预览功能的页面中。我真的越来越喜欢Blazor这个组件化的开发模式了好了就这些下次再见。