当前位置: 首页 > 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);}
}

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

http://www.xdnf.cn/news/920431.html

相关文章:

  • 模式选择器中 编辑一些操作 和文件菜单一些操作
  • 本地主机部署开源企业云盘Seafile并实现外部访问
  • 二进制与十进制转换指南:深入理解数字系统转换
  • 【赵渝强老师】使用obd快速体验OceanBase
  • 分享两个日常办公软件:uTools、PixPin
  • C#报价系统陈列展示成本核算系统项目管理系统纸品非纸品报价软件
  • WebRTC通话原理与入门难度实战指南
  • C++--list的使用及其模拟实现
  • 【Python训练营打卡】day46 @浙大疏锦行
  • PCA笔记
  • rl_sar实现sim2real的整体思路
  • [文献阅读] Emo-VITS - An Emotion Speech Synthesis Method Based on VITS
  • Java优化:双重for循环
  • 浅谈 React Suspense
  • Java高级 | 【实验七】Springboot 过滤器和拦截器
  • 【深度学习-Day 24】过拟合与欠拟合:深入解析模型泛化能力的核心挑战
  • PG 分区表的缺陷
  • Python网页自动化测试,DrissonPage库入门说明文档
  • Redis故障转移
  • 两种Https正向代理的实现原理
  • 文本切块技术(Splitter)
  • 运行示例程序和一些基本操作
  • 解决MySQL8.4报错ERROR 1524 (HY000): Plugin ‘mysql_native_password‘ is not loaded
  • Puppeteer API
  • Redis:现代应用开发的高效内存数据存储利器
  • springCloud2025+springBoot3.5.0+Nacos集成redis从nacos拉配置起服务
  • 【JavaWeb】Docker项目部署
  • LabVIEW主轴故障诊断案例
  • WPS中将在线链接转为图片
  • 备份还原打印机驱动