Blazor组件JS互操作JSON反序列化问题求助
问题分析与解决方案
错误根源
第一种方法的序列化错误
querySelectorAll返回的是NodeList(类数组对象),并非标准JS数组,Blazor无法将其反序列化为IJSObjectReference[]——因为NodeList没有实现数组的序列化协议,无法被自动转换为C#的数组类型。
第二种方法的"找不到get方法"错误
getElementsByTagName返回的是HTMLCollection,JS中访问其长度是直接取length属性,获取元素是用item(index)或直接索引(collection[index]),不存在名为get的方法,因此调用InvokeAsync("get", ...)会触发异常。
推荐解决方案:让JS直接返回结构化数据
最简洁高效的方式是让JS完成DOM数据提取并整理为JSON数组,直接传给C#,避免频繁的JS互操作调用,同时彻底解决序列化问题。
1. 修改JavaScript代码
将原JS函数改为返回整理好的数据数组:
window.storeAndCallCSharpMethod = () => { const dataArray = []; const tableBody = document.getElementById('table-body'); const rows = tableBody.getElementsByTagName('tr'); for (let i = 0; i < rows.length; i++) { const row = rows[i]; const inputs = row.getElementsByTagName('input'); const rowData = { Name: inputs[1].value, Quantity: inputs[2].value, UOM: inputs[3].value, RequiredBy: inputs[4].value }; dataArray.push(rowData); } return dataArray; }
2. 修改C#方法
直接接收JS返回的数组,Blazor会自动反序列化为List<Item>:
@code { List<Item> dataArray = new List<Item>(); private async Task StoreAndCallCSharpMethod() { // 直接获取JS返回的结构化数据 dataArray = await JSRuntime.InvokeAsync<List<Item>>("storeAndCallCSharpMethod"); // 处理数据(插入SQL等操作) foreach (var data in dataArray) { await insert.PRInsert(data.Name, data.Quantity, data.UOM, DateTime.Parse(data.RequiredBy)); Console.WriteLine($"{data.Name}, {data.Quantity}, {data.UOM}, {data.RequiredBy}"); } } }
备选方案:修正DOM元素的JS互操作(不推荐)
如果必须在C#中逐个操作DOM元素,需按照JS对象的正确访问方式修正代码:
private async Task StoreAndCallCSharpMethod() { var tableBody = await JSRuntime.InvokeAsync<IJSObjectReference>("eval", "document.getElementById('table-body')"); var rows = await tableBody.InvokeAsync<IJSObjectReference>("getElementsByTagName", "tr"); // 获取HTMLCollection的长度 int rowCount = await JSRuntime.InvokeAsync<int>("eval", "arguments[0].length", rows); for (int i = 0; i < rowCount; i++) { // 通过item方法获取指定索引的行元素 var row = await rows.InvokeAsync<IJSObjectReference>("item", i); var inputs = await row.InvokeAsync<IJSObjectReference>("getElementsByTagName", "input"); // 直接通过JS eval获取输入框的值 var name = await JSRuntime.InvokeAsync<string>("eval", "arguments[0][1].value", inputs); var quantity = await JSRuntime.InvokeAsync<string>("eval", "arguments[0][2].value", inputs); var uom = await JSRuntime.InvokeAsync<string>("eval", "arguments[0][3].value", inputs); var requiredByStr = await JSRuntime.InvokeAsync<string>("eval", "arguments[0][4].value", inputs); var rowData = new Item { Name = name, Quantity = quantity, UOM = uom, RequiredBy = DateTime.Parse(requiredByStr) }; dataArray.Add(rowData); } foreach (var data in dataArray) { Console.WriteLine($"{data.Name}, {data.Quantity}, {data.UOM}, {data.RequiredBy}"); } }
注意事项
- 确保
Item类的属性名与JS对象的键名完全匹配(大小写敏感),若需适配不同命名风格,可使用[JsonPropertyName]特性指定映射关系。 - 日期字符串解析:JS的
input[type="date"]返回ISO格式字符串(如2024-05-20),可直接用DateTime.Parse解析。 - Razor类库中的JS引用:需在宿主项目(Blazor Server的
_Host.cshtml或MAUI Blazor的index.html)中正确引用包含该JS函数的脚本文件。
内容的提问来源于stack exchange,提问作者Ghazi Jaffri
相关产品推荐
相关产品推荐

