MVC中Kendo Spreadsheet本地数据绑定增删改及性能优化问题
Kendo Spreadsheet复杂表头场景下的数据绑定优化方案(含增删改实现)
问题核心
当前通过服务器端循环逐行生成单元格的方式,在数据量较大时会导致页面渲染性能急剧下降;而远程AJAX绑定会覆盖自定义的复杂合并表头,需要找到既能保留表头结构,又能高效加载数据并支持增删改的方案。
优化方案:客户端批量加载数据+预定义表头
核心思路:服务器端仅提供JSON格式数据接口,客户端初始化Spreadsheet时先渲染好复杂合并表头,再通过Spreadsheet的客户端API批量写入数据,同时通过事件监听和AJAX交互实现增删改操作。
1. 服务器端调整
ViewModel(中文注释)
public class ViewModel { // 数据编号 public int ID { get; set; } // 名称 public int Name { get; set; } // 状态 public string Status { get; set; } }
控制器Action
// 渲染页面 public ActionResult Index() { return View(); } // 获取表格数据接口 public JsonResult GetSpreadsheetData() { List<ViewModel> data = service.GetData(); return Json(data, JsonRequestBehavior.AllowGet); } // 新增数据接口 [HttpPost] public JsonResult AddData(ViewModel model) { try { var newId = service.AddData(model); return Json(new { success = true, id = newId }); } catch (Exception ex) { return Json(new { success = false, message = ex.Message }); } } // 更新数据接口 [HttpPost] public JsonResult UpdateData(ViewModel model) { try { service.UpdateData(model); return Json(new { success = true }); } catch (Exception ex) { return Json(new { success = false, message = ex.Message }); } } // 删除数据接口 [HttpPost] public JsonResult DeleteData(int id) { try { service.DeleteData(id); return Json(new { success = true }); } catch (Exception ex) { return Json(new { success = false, message = ex.Message }); } }
2. 视图端实现
在视图中先定义好复杂合并表头,再通过AJAX拉取数据并批量写入工作表,同时实现增删改的交互逻辑:
@model dynamic @section body { @(Html.Kendo().Spreadsheet() .Columns(3) .Name("DataExcel") .HtmlAttributes(new { style = "width:auto; height: 770px;" }) .Toolbar(true) // 启用工具栏,可自定义增删按钮 .Sheetsbar(false) .Events(e => e .Select("onSelect") .Change("onDataChange")) .Sheets(sheets => { sheets.Add() .Name("DataSheet") .Columns(columns => { columns.Add().Width(50); columns.Add().Width(100); columns.Add().Width(100); }) .Rows(rows => { // 自定义复杂合并表头(示例结构,根据实际需求调整) rows.Add().Height(60).Cells(cells => { // 合并第1行3列作为主标题 cells.Add() .Value("业务数据汇总") .HorizontalAlign(SpreadsheetHorizontalAlign.Center) .VerticalAlign(SpreadsheetVerticalAlign.Center) .Bold(true) .ColSpan(3); }); rows.Add().Height(40).Cells(cells => { cells.Add().Value("编号").Bold(true).HorizontalAlign(SpreadsheetHorizontalAlign.Center); cells.Add().Value("名称").Bold(true).HorizontalAlign(SpreadsheetHorizontalAlign.Center); cells.Add().Value("状态").Bold(true).HorizontalAlign(SpreadsheetHorizontalAlign.Center); }); }); }) ) <script> $(document).ready(function() { var spreadsheet = $("#DataExcel").data("kendoSpreadsheet"); var sheet = spreadsheet.activeSheet(); // 加载数据 $.ajax({ url: "@Url.Action("GetSpreadsheetData")", type: "GET", success: function(data) { if (!data || data.length === 0) return; // 从第3行开始写入数据(前2行为表头) const startRow = 2; // 将数据转换为二维数组,方便批量写入 const dataRows = data.map(item => [item.ID, item.Name, item.Status]); // 批量写入数据到工作表 sheet.range(startRow, 0, dataRows.length, 3).values(dataRows); // 统一设置数据行样式 sheet.range(startRow, 0, dataRows.length, 3) .verticalAlign("center") .color("black"); // 状态列加粗 sheet.range(startRow, 2, dataRows.length, 1).bold(true); } }); }); // 数据修改事件监听 function onDataChange(e) { const range = e.range; const sheet = e.sender.activeSheet(); const rowIndex = range.top; // 跳过表头行 if (rowIndex < 2) return; // 获取当前行完整数据 const rowData = sheet.range(rowIndex, 0, 1, 3).values()[0]; const updateModel = { ID: rowData[0], Name: rowData[1], Status: rowData[2] }; // 提交更新请求 $.ajax({ url: "@Url.Action("UpdateData")", type: "POST", data: updateModel, success: res => { if (!res.success) alert("更新失败:" + res.message); }, error: () => alert("更新请求出错") }); } // 新增行操作(可绑定到工具栏按钮或自定义按钮) function addNewRow() { const spreadsheet = $("#DataExcel").data("kendoSpreadsheet"); const sheet = spreadsheet.activeSheet(); const lastRow = sheet.usedRange().bottom; // 在最后一行插入新行 sheet.insertRow(lastRow + 1, 1); // 设置新行样式 sheet.range(lastRow + 1, 0, 1, 3) .verticalAlign("center") .color("black"); sheet.range(lastRow + 1, 2, 1, 1).bold(true); } // 删除行操作(可绑定到工具栏按钮或右键菜单) function deleteSelectedRow() { const spreadsheet = $("#DataExcel").data("kendoSpreadsheet"); const sheet = spreadsheet.activeSheet(); const selectedRange = sheet.selectedRange(); const rowIndex = selectedRange.top; // 禁止删除表头行 if (rowIndex < 2) { alert("无法删除表头行"); return; } const rowId = sheet.range(rowIndex, 0).value(); // 未保存的新增行直接删除 if (!rowId) { sheet.deleteRow(rowIndex, 1); return; } if (confirm("确定删除该行数据?")) { $.ajax({ url: "@Url.Action("DeleteData")", type: "POST", data: { id: rowId }, success: res => { if (res.success) { sheet.deleteRow(rowIndex, 1); } else { alert("删除失败:" + res.message); } }, error: () => alert("删除请求出错") }); } } // 原选择事件逻辑保留 function onSelect(e) { // 原有业务逻辑写在这里 } </script> }
3. 方案优势
- 性能提升:客户端批量写入数据避免了服务器端循环生成大量DOM节点,数据量越大性能提升越明显。
- 表头安全:预定义的复杂合并表头不会被数据覆盖,完全保留自定义结构。
- 完整操作闭环:通过客户端事件和AJAX交互,实现了数据的增删改功能,配合Kendo Spreadsheet的原生API简化了行操作逻辑。
内容的提问来源于stack exchange,提问作者user1223445
相关产品推荐
相关产品推荐

