Blazor博客编辑组件提交空标题触发removeChild空引用错误致应用冻结
问题分析
提交空标题的博客时出现的TypeError: Cannot read properties of null (reading 'removeChild')错误,本质是Blazor渲染过程中JS互操作异常,通常是组件状态未正确同步或调用时机不当导致。结合代码来看,核心问题有两点:
- 表单验证与编辑器内容获取的顺序逻辑错误,导致验证失败后编辑器DOM状态异常
- 未对编辑器组件引用做空值检查,增加了未初始化调用的风险
解决方案
1. 调整操作顺序,先更新模型再验证
当前代码先执行表单验证,再获取编辑器内容更新模型,这会导致验证基于旧的模型数据,同时验证触发的重新渲染可能干扰编辑器的JS操作。应先同步编辑器内容到模型,再执行完整的表单验证。
2. 增加组件引用的空值检查
确保调用编辑器方法前,组件引用已正确初始化,避免空引用引发的后续错误。
3. 优化异常处理逻辑
避免捕获异常后直接返回,应给出明确的错误提示,同时保证组件状态正常恢复。
修改后的代码
@using BlazorBlog.Application.Features.Blogs.Commands.Edit @inherits MudComponentBase @inject IValidationService Validator @inject IMediator Mediator <MudDialog style="min-height: 650px;"> <DialogContent> <MudForm Model="@Model" @ref="@_form" Validation="@(Validator.ValidateValue(Model))"> <MudGrid> <MudItem xs="12"> <MudTextField Label="Blog Title" @bind-Value="Model.Title" For="@(() => Model.Title)" Required RequiredError="@string.Format(ConstantString.RequiredText, "Blog Title")"> </MudTextField> </MudItem> <MudItem xs="12"> <BlazoredTextEditor @ref="@RichEditor"> <ToolbarContent> <span class="ql-formats"> <select class="ql-font"> <option selected=""></option> <option value="serif"></option> <option value="monospace"></option> </select> <select class="ql-size"> <option value="small"></option> <option selected=""></option> <option value="large"></option> <option value="huge"></option> </select> </span> <span class="ql-formats"> <button class="ql-bold"></button> <button class="ql-italic"></button> <button class="ql-underline"></button> <button class="ql-strike"></button> </span> <span class="ql-formats"> <select class="ql-color"></select> <select class="ql-background"></select> </span> <span class="ql-formats"> <button class="ql-list" value="ordered"></button> <button class="ql-list" value="bullet"></button> <button class="ql-indent" value="-1"></button> <button class="ql-indent" value="+1"></button> <select class="ql-align"> <option selected=""></option> <option value="center"></option> <option value="right"></option> <option value="justify"></option> </select> </span> <span class="ql-formats"> <button class="ql-link"></button> </span> </ToolbarContent> <EditorContent> @((MarkupString)Model.Description) </EditorContent> </BlazoredTextEditor> </MudItem> </MudGrid> </MudForm> </DialogContent> <DialogActions> <MudButton Variant="Variant.Outlined" OnClick="Cancel">@ConstantString.Cancel</MudButton> <MudLoadingButton Variant="Variant.Outlined" Loading="@_saving" OnClick="Submit">@ConstantString.SaveChanges</MudLoadingButton> </DialogActions> </MudDialog> @code { [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = default!; [EditorRequired][Parameter] public EditBlogCommand Model { get; set; } = default!; [Parameter] public Action? Refresh { get; set; } private MudForm? _form; private bool _saving; private BlazoredTextEditor? RichEditor; // 增加nullable标记 private async Task Submit() { try { _saving = true; // 1. 先检查编辑器引用是否存在 if (RichEditor == null) { Snackbar.Add("编辑器未初始化,请稍后重试", Severity.Error); return; } // 2. 先获取编辑器内容更新模型 try { Model.Description = await RichEditor.GetHTML(); } catch (Exception ex) { Snackbar.Add($"获取编辑器内容失败: {ex.Message}", Severity.Error); return; } // 3. 再执行表单验证 await _form!.Validate().ConfigureAwait(false); if (!_form.IsValid) { return; } // 4. 提交命令 var result = await Mediator.Send(Model); if (result.Succeeded) { MudDialog.Close(DialogResult.Ok(true)); Snackbar.Add(ConstantString.SaveSuccess, Severity.Info); Refresh?.Invoke(); } else { Snackbar.Add(result.ErrorMessage, Severity.Error); } } finally { _saving = false; } } private void Cancel() { MudDialog.Cancel(); } }
额外建议
- 检查Blazored Text Editor的版本,确保使用最新稳定版,部分旧版本存在类似的DOM操作异常
- 若仍出现渲染问题,可尝试在编辑器组件上添加
@key="Model.Id"(或唯一标识),帮助Blazor正确跟踪组件状态
内容的提问来源于stack exchange,提问作者Sachihiro
相关产品推荐
相关产品推荐

