.NET Core Razor点击按钮执行C#方法及无刷新更新表格方案
Hey, 我一眼就看出你当前的问题出在哪了——你写的@Model.RuleStepMoveUp()是Razor服务器端渲染代码,页面加载的时候服务器就会执行这个方法,根本等不到你点击按钮。这就是为啥页面一加载就触发了方法,还抛出空引用异常——那会儿子项的Model数据大概率还没初始化好呢。
下面给你一套完整的解决方案,既能实现点击按钮才执行后端方法,还能做到无刷新更新表格:
第一步:把后端方法改成Razor Pages规范的Post Handler
因为你用的是Razor Pages项目,最好遵循它的Handler命名规则,把移动逻辑改成POST请求的Handler,这样前端可以通过AJAX安全调用,还能避免GET请求的副作用。
比如在Index.cshtml.cs里调整方法:
// 上移操作的Post Handler,接收子项ID参数 public async Task<IActionResult> OnPostMoveUpAsync(int detailId) { // 1. 找到要移动的子项 var targetStep = await _context.RuleSteps.FindAsync(detailId); if (targetStep == null) { return NotFound("子项不存在"); } // 2. 找到同主项的上一个子项(按排序值倒序找第一个比当前小的) var prevStep = await _context.RuleSteps .Where(s => s.RuleId == targetStep.RuleId && s.SortOrder < targetStep.SortOrder) .OrderByDescending(s => s.SortOrder) .FirstOrDefaultAsync(); if (prevStep != null) { // 3. 交换两个子项的排序值 (targetStep.SortOrder, prevStep.SortOrder) = (prevStep.SortOrder, targetStep.SortOrder); await _context.SaveChangesAsync(); } // 4. 返回更新后的同主项子项列表,供前端更新表格 var updatedSteps = await _context.RuleSteps .Where(s => s.RuleId == targetStep.RuleId) .OrderBy(s => s.SortOrder) .ToListAsync(); return new JsonResult(updatedSteps); } // 下移操作同理 public async Task<IActionResult> OnPostMoveDownAsync(int detailId) { var targetStep = await _context.RuleSteps.FindAsync(detailId); if (targetStep == null) { return NotFound("子项不存在"); } var nextStep = await _context.RuleSteps .Where(s => s.RuleId == targetStep.RuleId && s.SortOrder > targetStep.SortOrder) .OrderBy(s => s.SortOrder) .FirstOrDefaultAsync(); if (nextStep != null) { (targetStep.SortOrder, nextStep.SortOrder) = (nextStep.SortOrder, targetStep.SortOrder); await _context.SaveChangesAsync(); } var updatedSteps = await _context.RuleSteps .Where(s => s.RuleId == targetStep.RuleId) .OrderBy(s => s.SortOrder) .ToListAsync(); return new JsonResult(updatedSteps); }
第二步:前端用AJAX触发方法,无刷新更新表格
先给子项表格加个ID,方便后续动态更新;然后给按钮绑定点击事件,用AJAX调用后端Handler,拿到更新后的数据再刷新表格内容:
1. 调整表格HTML结构
<!-- 给表格加ID,方便后续操作 --> <table id="ruleStepsTable" class="table"> <thead> <tr> <th>子项名称</th> <th>排序值</th> <th>操作</th> </tr> </thead> <tbody> @foreach (var step in Model.CurrentRuleSteps) { <tr data-step-id="@step.Id"> <td>@step.Name</td> <td>@step.SortOrder</td> <td> <!-- 用data-id存储子项ID,方便JS获取 --> <button class="btn btn-sm btn-primary btn-move-up" data-id="@step.Id">上移</button> <button class="btn btn-sm btn-secondary btn-move-down" data-id="@step.Id">下移</button> </td> </tr> } </tbody> </table> <!-- 手动添加防CSRF令牌(如果页面没有form标签的话) --> @Html.AntiForgeryToken()
2. 编写AJAX逻辑
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function() { // 绑定上移按钮点击事件 bindMoveEvents(); // 封装绑定事件的函数,方便动态更新后重新绑定 function bindMoveEvents() { $('.btn-move-up').off('click').click(function() { performMove($(this).data('id'), 'MoveUp'); }); $('.btn-move-down').off('click').click(function() { performMove($(this).data('id'), 'MoveDown'); }); } // 封装移动操作的AJAX逻辑 function performMove(detailId, handlerName) { $.ajax({ url: '/Index?handler=' + handlerName, // Razor Pages Handler路由格式 type: 'POST', data: { detailId: detailId }, headers: { // 必须携带防CSRF令牌,否则请求会被拒绝 'RequestVerificationToken': $('input[name="__RequestVerificationToken"]').val() }, success: function(updatedSteps) { // 成功后更新表格内容 updateRuleStepsTable(updatedSteps); alert('操作成功!'); }, error: function(xhr) { alert('操作失败:' + xhr.responseText); } }); } // 封装表格更新逻辑 function updateRuleStepsTable(steps) { var tbody = $('#ruleStepsTable tbody'); tbody.empty(); // 清空旧内容 // 循环生成新的表格行 $.each(steps, function(index, step) { var rowHtml = `<tr data-step-id="${step.Id}"> <td>${step.Name}</td> <td>${step.SortOrder}</td> <td> <button class="btn btn-sm btn-primary btn-move-up" data-id="${step.Id}">上移</button> <button class="btn btn-sm btn-secondary btn-move-down" data-id="${step.Id}">下移</button> </td> </tr>`; tbody.append(rowHtml); }); // 重新绑定按钮事件(因为新行是动态生成的) bindMoveEvents(); } }); </script>
关键注意事项
- 防CSRF保护:Razor Pages默认开启了CSRF防护,所以所有POST请求必须携带
__RequestVerificationToken,要么通过页面的form标签自动生成,要么手动添加@Html.AntiForgeryToken()。 - 动态元素事件绑定:因为表格行是动态更新的,新生成的按钮需要重新绑定点击事件,否则点击会无效,上面的代码用
off('click').click()解决了这个问题。 - Handler命名规则:Razor Pages的Handler方法必须以
OnPost或OnGet开头,前端路由用?handler=XXX(XXX是方法名去掉OnPost/OnGet后的部分,比如OnPostMoveUpAsync对应handler=MoveUp)。
这样改完之后,只有点击按钮时才会调用后端的C#方法,而且页面不用刷新就能实时更新子项表格的顺序,体验非常流畅。
内容的提问来源于stack exchange,提问作者PRHMN
相关产品推荐
相关产品推荐

