Blazor WebAssembly无需新建Razor页实现动态表单打印需求
Blazor WebAssembly 跨页面数据无显式页面打印方案
核心思路
通过后端API生成包含所有需要整合数据的打印用HTML字符串,前端通过JS互操作动态创建隐藏DOM元素加载该HTML,直接触发打印后自动清理元素,无需新建Razor页。
1. 后端实现(生成打印HTML)
创建API接口,从各数据源拉取数据并构建结构化的打印HTML(可硬拼字符串或用Razor视图渲染):
using Microsoft.AspNetCore.Mvc; using YourProject.Services; namespace YourProject.Controllers { [ApiController] [Route("api/[controller]")] public class PrintController : ControllerBase { private readonly IDataService1 _dataService1; private readonly IDataService2 _dataService2; public PrintController(IDataService1 dataService1, IDataService2 dataService2) { _dataService1 = dataService1; _dataService2 = dataService2; } [HttpGet("integrated-form")] public async Task<IActionResult> GetIntegratedPrintForm() { // 从不同模块获取需要整合的数据 var module1Data = await _dataService1.GetAsync(); var module2Data = await _dataService2.GetAsync(); // 构建打印专属HTML(含打印样式) var printHtml = $@" <!DOCTYPE html> <html> <head> <meta charset='UTF-8'> <title>整合数据打印单</title> <style> /* 基础打印样式 */ body {{ font-family: Arial, sans-serif; margin: 0; padding: 20px; }} .section {{ margin-bottom: 30px; border-bottom: 1px solid #ddd; padding-bottom: 15px; }} h1 {{ text-align: center; color: #333; }} /* 适配打印媒体 */ @media print {{ body {{ padding: 0; }} .section {{ page-break-inside: avoid; }} }} </style> </head> <body> <h1>整合业务数据打印单</h1> <div class='section'> <h2>模块1信息</h2> <p>名称: {module1Data.Name}</p> <p>创建时间: {module1Data.CreatedTime:yyyy-MM-dd HH:mm}</p> <p>详情: {module1Data.Description}</p> </div> <div class='section'> <h2>模块2信息</h2> <p>编号: {module2Data.Id}</p> <p>状态: {module2Data.Status}</p> <p>备注: {module2Data.Remarks}</p> </div> </body> </html>"; return Ok(printHtml); } } }
注:如果HTML布局复杂,推荐用Razor视图渲染:创建
.cshtml视图,使用IRazorViewEngine将视图渲染为字符串返回,避免硬拼字符串的维护问题。
2. 前端JS互操作实现(无显示打印)
在wwwroot/js/print-utils.js中添加打印专用JS函数:
window.printHiddenHtml = function(htmlContent) { // 创建隐藏的iframe容器 const printIframe = document.createElement('iframe'); printIframe.style.position = 'absolute'; printIframe.style.width = '0'; printIframe.style.height = '0'; printIframe.style.border = '0'; printIframe.style.display = 'none'; document.body.appendChild(printIframe); // 加载HTML内容 const iframeDoc = printIframe.contentDocument || printIframe.contentWindow.document; iframeDoc.open(); iframeDoc.write(htmlContent); iframeDoc.close(); // 内容加载完成后触发打印,打印后清理元素 printIframe.onload = function() { printIframe.contentWindow.print(); // 延迟移除避免打印中断 setTimeout(() => document.body.removeChild(printIframe), 1500); }; };
3. Blazor组件调用(打印按钮逻辑)
在你的打印按钮所在组件中,注入HttpClient和IJSRuntime,实现点击触发逻辑:
@inject HttpClient Http @inject IJSRuntime JSRuntime <MudButton OnClick="TriggerIntegratedPrint" Variant="Variant.Filled" Color="Color.Primary" Icon="@Icons.Material.Filled.Print"> 打印整合表单 </MudButton> @code { private async Task TriggerIntegratedPrint() { try { // 调用后端API获取打印HTML var printHtml = await Http.GetStringAsync("api/print/integrated-form"); // 调用JS执行无显示打印 await JSRuntime.InvokeVoidAsync("window.printHiddenHtml", printHtml); } catch (Exception ex) { // 这里可以用MudBlazor的Snackbar提示错误 // await Snackbar.Add($"打印失败: {ex.Message}", Severity.Error); } } }
关键注意事项
- 打印样式必须适配打印媒体:使用
@media print规则调整打印时的布局、边距等,避免屏幕样式干扰。 - 后端生成HTML时要确保字符编码正确(UTF-8),避免乱码。
- 动态创建的iframe要在打印完成后及时清理,避免DOM冗余。
内容的提问来源于stack exchange,提问作者Gagandeep Singh Bagga
相关产品推荐
相关产品推荐

