当前位置: 首页 > news >正文

Bootstrap Blazor中实现富文本框Editor组件的内容导出为docx格式的Word文档

        Bootstrap Blazor中的富文本框 Editor 组件,功能强大,能够在其中创建文本、表格和图片等,进而可以作为一个简单的Word编辑器使用,但是不支持导出。具体用法详见官网:SiteTitle。下面用BB的项目模板进行演示,模板下载地址:SiteTitle。

1、安装所需的库并引用

        a、BootstrapBlazor.SummerNote(9.0.4):富文本框 Editor 组件是对Summernotote组件的二次封装,依赖于这个库;注意在 App.razor 中引入jQuery的js文件:

<script src="_content/BootstrapBlazor.SummerNote/js/jquery-3.6.0.min.js"></script>

        b、HtmlToOpenXml.dll(3.2.5):用于将HTML转为docx格式的Word对应的XML。

        c、DocumentFormat.OpenXml(3.3.0):用于将b中的XML转换并保存为Word文档。

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml;
using HtmlToOpenXml;

2、简单写一个测试页

        a、RichText.razor文件,包含一个 Editor 组件和一个导出按钮:

@page "/richText"
@attribute [TabItemOption(Text = "RichText")]<div style="position: relative;width: 100%;height: 600px;"><div><Button Text="导出富文本内容" IsAsync="true" OnClick="@OnClickToExportRichText"></Button></div><div style="margin-top: 10px;"><Editor IsEditor="true" Height="400" ShowSubmit="false" PlaceHolder="请填充内容" @bind-Value="@TextValue" /></div>
</div>

        b、RichText.razor.cs文件:

using BootstrapBlazor.Components;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml;
using HtmlToOpenXml;
using Microsoft.AspNetCore.Components;
using System.Diagnostics.CodeAnalysis;namespace BootstrapBlazorApp.Server.Components.Pages
{public partial class RichText{// BB的下载服务[Inject][NotNull]private DownloadService _downloadService { get; set; }// 双向绑定的 Editor 组件的内容private string? TextValue { get; set; }private async Task OnClickToExportRichText(){try{if (string.IsNullOrWhiteSpace(TextValue)){throw new ArgumentNullException(nameof(TextValue));}// 将富文本的代码块封装到html的body中string htmlContent = $"<html><body>{TextValue}</body></html>";// 用于存文件流using Stream stream = new MemoryStream();// 创建一个新的Word文档using (WordprocessingDocument wordDoc = WordprocessingDocument.Create(stream, WordprocessingDocumentType.Document)){// 添加主文档部件MainDocumentPart mainPart = wordDoc.AddMainDocumentPart();mainPart.Document = new DocumentFormat.OpenXml.Wordprocessing.Document();// 使用HtmlConverter将HTML转换为XMLHtmlConverter converter = new HtmlConverter(mainPart);// 解析body中的内容,也就是 Editor 组件中的HTML代码段await converter.ParseBody(htmlContent);// 保存文档流mainPart.Document.Save();}// 指针位置0stream.Position = 0;// 流式下载docx文件DownloadOption option = new DownloadOption();option.FileStream = stream;option.FileName = $"富文本{DateTime.Now.ToString("yyyyMMddHHmmss")}.docx";await _downloadService.DownloadFromStreamAsync(option);}catch (Exception ex){System.Console.WriteLine(ex.Message);}}}
}

        c、页面

 3、原理

        Editor 组件的原理是将其里面的内容转化为HTML代码片段,因此实际上的导出思路是将HTML转为Word。

        通过单击 Editor 中的源代码查看按钮,我们可以看到上面一行文字被转化为了下面一行HTML代码段:

        但是不能直接从HTML转为Word,Word内部对应(接收)的是一种特殊格式的XML,故需要经过一次中转:HTML——>XML——>Word。

4、测试

        往 Editor 组件框中粘贴一些文本,Ctrl+A全选文本改为Arial样式(这个样式与原本文更贴近):

        然后单击【导出富文本内容】按钮进行导出,是一个docx格式的Word文档,内容如下:

        可以看到,字体、颜色、格式等样式基本都被保留下来了,效果还是不错的。

5、扩展

        上述的方式能够将 Editor 组件中的内容添加到docx格式的Word文档中,但是缺少Header和Footer。有时我们想要往特定的有头有尾的文档中填充内容,比如有下面的Header和Footer的docx格式的Word模板文档:

        

        在wwwroot中添加模板文件:

        注入环境变量:

/// <summary>
/// Web环境
/// </summary>
[Inject]
[NotNull]
private IWebHostEnvironment _env { get; set; }

        这时只需要将导出方法改为如下:

private async Task OnClickToExportRichText()
{try{if (string.IsNullOrWhiteSpace(TextValue)){throw new ArgumentNullException(nameof(TextValue));}// 将富文本的代码块封装到html的body中string htmlContent = $"<html><body>{TextValue}</body></html>";// wwwroot中模板的相对路径和绝对路径string docxPath = "Template/头尾模板 - 复制.docx";string tempPath = Path.Combine(_env.WebRootPath, docxPath);// 打开现有的模板文档using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(tempPath, true)){// 添加主文档部件MainDocumentPart mainPart = wordDoc.MainDocumentPart;// 使用HtmlConverter将HTML转换为XMLHtmlConverter converter = new HtmlConverter(mainPart);// 解析body中的内容,也就是 Editor 组件中的HTML代码段await converter.ParseBody(htmlContent);// 保存文档mainPart.Document.Save();}// Url下载docx文件DownloadOption option = new DownloadOption();option.Url = docxPath;option.FileName = $"富文本{DateTime.Now.ToString("yyyyMMddHHmmss")}.docx";await _downloadService.DownloadFromUrlAsync(option);}catch (Exception ex){System.Console.WriteLine(ex.Message);}
}

        这种方式是直接在模板文档中进行插入操作,会改变原本模板文件,而且每次导出都会在上一次导出的基础上进行Append,故不推荐。

        当然也可以使用 Body 的 RemoveAllChildren 方法清空子元素:

mainPart.Document.Body.RemoveAllChildren<DocumentFormat.OpenXml.Wordprocessing.Paragraph>();

        如果不想改变原模板文件,则需要每次复制一个模板文件出来,用于接收数据。这样又会导致文件累积,生成的文件越来越多,因此需要在下载后进行删除。

        另一种方式是使用DocX库(免费的),可以进行流操作,减少文件操作。需要安装DocX(4.0.25105.5786)库并引用:

using Xceed.Words.NET;

        修改导出方法如下:

private async Task OnClickToExportRichText()
{try{if (string.IsNullOrWhiteSpace(TextValue)){throw new ArgumentNullException(nameof(TextValue));}// 将富文本的代码块封装到html的body中string htmlContent = $"<html><body>{TextValue}</body></html>";// 用于存文件流using Stream stream = new MemoryStream();// 创建一个新的Word文档using (WordprocessingDocument wordDoc = WordprocessingDocument.Create(stream, WordprocessingDocumentType.Document)){// 添加主文档部件MainDocumentPart mainPart = wordDoc.AddMainDocumentPart();mainPart.Document = new DocumentFormat.OpenXml.Wordprocessing.Document();// 使用HtmlConverter将HTML转换为XMLHtmlConverter converter = new HtmlConverter(mainPart);// 解析body中的内容,也就是 Editor 组件中的HTML代码段await converter.ParseBody(htmlContent);// 保存文档流mainPart.Document.Save();}// 指针位置0stream.Position = 0;// 加载上面的文档流DocX docx1 = DocX.Load(stream);// 加载头尾模板文件string tempPath = Path.Combine(_env.WebRootPath, "Template/头尾模板.docx");DocX docx = DocX.Load(tempPath);// 将 Editor 中的内容插入到模板文档中docx.InsertDocument(docx1, true, false);// 另存为流using var ms = new MemoryStream();docx.SaveAs(ms);ms.Position = 0;// 流式下载docx文件DownloadOption option = new DownloadOption();option.FileStream = ms;option.FileName = $"富文本{DateTime.Now.ToString("yyyyMMddHHmmss")}.docx";await _downloadService.DownloadFromStreamAsync(option);}catch (Exception ex){System.Console.WriteLine(ex.Message);}
}

        最终,两种方式导出的效果一致,如下图:

相关文章:

  • Spring Security深度解析:构建企业级安全框架
  • CCPC chongqing 2025 H
  • c++ 静态成员变量
  • xss漏洞学习
  • 什么是可恢复保险丝
  • ELF文件,静态链接(Linux)
  • 关于 ​​Thread 与 Runnable​​ 以及 ​​线程生命周期​​ 的详细说明与示例
  • 实战二:开发网页端界面完成黑白视频转为彩色视频
  • 6.7-leetcodeT3170
  • AcWing--数据结构1
  • 淘晶驰的串口显示屏T0 T1 K0 X2 X3 X5之间有何区别 各自的优势是啥 划分的依据是啥
  • CAN转PROFINET协议网关之PROFINET转CANfree组态秘诀
  • Go 语言 sync.WaitGroup 深度解析
  • spring:实例工厂方法获取bean
  • 源码级拆解:如何搭建高并发「数字药店+医保购药」一体化平台?
  • hmdp知识点
  • 深入剖析 RocketMQ 中的 DefaultMQPushConsumerImpl:消息推送消费的核心实现
  • SAP 在 AI 与数据统一平台上的战略转向
  • 测试(面经 八股)
  • 2025年—Comfyui聚合插件:Comfyui-LayerStyle 超多实用功能 | 附各功能模型
  • 局机关网站建设改进措施/2345浏览器影视大全
  • 地方门户网站推广/营销策略理论
  • 网站文章列表和图片列表排版切换代码/自媒体营销模式有哪些
  • 邢台经济开发区网站/网络营销品牌推广
  • 南安淘宝网站建设/关键词免费网站
  • 哪些网站建设公司/网络推广引流有哪些渠道