如何在Razor页面(CSHTML)的JS函数中调用C#的UpdateRecursiveData方法
问题1解答:JS函数内无法直接调用服务端定义的C#函数
Razor页面的C#代码执行时机是服务端渲染阶段,也就是页面还没发送到用户浏览器的时候就已经执行完毕。你写在JS函数内的@UpdateRecursiveData(tn)会在页面渲染时直接执行,而此时tn是仅存在于浏览器端的JS变量,服务端完全无法识别,自然会报错。等JS在浏览器端运行时,所有C#代码已经执行完成,不存在可以调用的服务端C#方法。
问题2解答:实现需求的具体方案
你的核心需求是在勾选复选框后,动态渲染对应节点的子节点,推荐将原来服务端的UpdateRecursiveData逻辑改写为JS函数,接口请求成功后拿到子节点数据,直接用JS渲染DOM,性能更高逻辑也更清晰。
具体修改代码如下:
- 首先修改后端
OnPostMyAction接口,返回新增的子节点JSON数据:
public async Task<IActionResult> OnPostMyAction(string itemName,bool deploy) { if (TempData["TreeData"] != null) tree_List = TempData.Get<List<TreeNode>>("TreeData"); TreeNode upTree=null; foreach (var item in tree_List) { if (item.board_id == itemName) { upTree = item; item.deployment = deploy; } } List<TreeNode> newNodes = new List<TreeNode>(); if (deploy&&upTree.loadOn==false) { if(upTree!=null) upTree.deployment = true; IQueryable<tbl_tree> iqueryTree; iqueryTree = _context.tbl_tree.Where(x => x.upcode == itemName); var datas =await iqueryTree.ToListAsync(); for (int i = 0; i < datas.Count; i++) { TreeNode treeNode = new TreeNode(datas[i].name); treeNode.board_id = datas[i].icd11; tree_List.Add(treeNode); newNodes.Add(treeNode); } TempData.Set("TreeData", tree_List); } // 返回新增的子节点数据 return new JsonResult(newNodes); }
- 改写前端代码,新增JS版递归渲染函数,删除原来无效的
@UpdateRecursiveData(tn)调用:
// 新增JS版递归渲染函数,代替原来的服务端C#函数 function renderRecursiveData(parentLoaderId, nodeList) { const parentEl = document.getElementById(parentLoaderId).parentNode; nodeList.forEach(tn => { // 渲染复选框 const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.onclick = () => requestMyAction(tn.board_id, checkbox.checked, `loader-${tn.dataName}`); parentEl.appendChild(checkbox); // 渲染loader元素 const loader = document.createElement('div'); loader.className = 'loader'; loader.style.display = 'none'; loader.id = `loader-${tn.dataName}`; loader.innerText = tn.dataName; parentEl.appendChild(loader); // 插入换行 parentEl.appendChild(document.createElement('br')); // 递归渲染子节点 if(tn.subTreeNodes && tn.subTreeNodes.length > 0) { renderRecursiveData(loader.id, tn.subTreeNodes); } }) } function requestMyAction(itemId, isChecked, loaderId) { document.getElementById(loaderId).style.display = "inline-block"; var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (this.readyState === 4) { document.getElementById(loaderId).style.display = "none"; if (this.status === 200) { // 接口请求成功后调用渲染函数 const newNodes = JSON.parse(this.responseText); renderRecursiveData(loaderId, newNodes); } } }; var url = '@Url.Page("./TreeExample", "MyAction")'; xhr.open('POST', url); xhr.setRequestHeader('RequestVerificationToken', '@Xsrf.GetAndStoreTokens(Model.HttpContext).RequestToken'); var data = new FormData(); data.append('itemName', itemId); data.append('deploy', isChecked); xhr.send(data); }
问题3解答:可以让渲染逻辑晚于接口请求完成
上面的代码已经实现了该需求,只需要把渲染操作放到XHR的readyState === 4且status === 200的回调函数中即可,此时接口已经完成请求,返回数据也已经拿到,完全符合执行时机要求。
内容的提问来源于stack exchange,提问作者로다현
相关产品推荐
相关产品推荐

