如何在Razor页面中不重定向调用C#函数,实现树形结构子项的异步加载与视图更新
Hey there! Let's sort out this treeview lazy loading problem without those annoying page redirects. Here's a practical, step-by-step solution tailored to your ASP.NET Core Razor Pages setup:
1. Rewrite Your Backend Handler (cshtml.cs)
Instead of using RedirectToPage, we'll create a handler that returns JSON data directly—this lets us fetch child items asynchronously without reloading the whole page.
// Inject your EF Core DbContext via constructor first private readonly YourDbContext _dbContext; public YourPageModel(YourDbContext dbContext) { _dbContext = dbContext; } // This handler will return child items for a given parent ID public IActionResult OnPostLoadChildItems(int parentId) { // Use EF Core to query child items based on the parent ID var childItems = _dbContext.YourEntity .Where(item => item.ParentId == parentId) .Select(item => new { Id = item.Id, Name = item.Name, // Add a flag to check if this item has its own children HasChildren = _dbContext.YourEntity.Any(child => child.ParentId == item.Id) }) .ToList(); // Optional: Add permission checks here if needed // if (!Model.authority) return Forbid(); return new JsonResult(childItems); }
2. Update Your Frontend (cshtml)
We'll add click events to the ▶ buttons, use AJAX to fetch data, and dynamically update the DOM without page refreshes. Keep your existing permission check intact!
HTML for Treeview
@if (Model.authority) { <ul class="treeview"> @foreach (var mainItem in Model.MainItems) { <li> <button class="expand-btn" data-parent-id="@mainItem.Id">▶</button> <span>@mainItem.Name</span> <!-- Container to load child items into --> <div id="child-container-@mainItem.Id" class="child-items"></div> </li> } </ul> }
JavaScript for Async Loading
Add this at the bottom of your cshtml file (or link a separate JS file):
// Bind click events to all expand buttons document.querySelectorAll('.expand-btn').forEach(btn => { btn.addEventListener('click', async function() { const parentId = this.getAttribute('data-parent-id'); const childContainer = document.getElementById(`child-container-${parentId}`); // Toggle visibility if items are already loaded if (childContainer.classList.contains('loaded')) { childContainer.style.display = childContainer.style.display === 'none' ? 'block' : 'none'; this.textContent = childContainer.style.display === 'block' ? '▼' : '▶'; return; } try { // Send POST request to our backend handler const response = await fetch(window.location.pathname + '?handler=LoadChildItems', { method: 'POST', headers: { 'Content-Type': 'application/json', // Include anti-forgery token required by Razor Pages 'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value }, body: JSON.stringify({ parentId: parentId }) }); if (!response.ok) throw new Error('Failed to load child items'); const childItems = await response.json(); // Render child items dynamically let childHtml = '<ul>'; childItems.forEach(item => { const expandIcon = item.HasChildren ? '<button class="expand-btn" data-parent-id="' + item.Id + '">▶</button>' : ''; childHtml += ` <li> ${expandIcon} <span>${item.Name}</span> ${item.HasChildren ? `<div id="child-container-${item.Id}" class="child-items"></div>` : ''} </li> `; }); childHtml += '</ul>'; childContainer.innerHTML = childHtml; childContainer.classList.add('loaded'); this.textContent = '▼'; // Switch to collapse icon // Bind click events to newly created expand buttons document.querySelectorAll(`#child-container-${parentId} .expand-btn`).forEach(newBtn => { newBtn.addEventListener('click', this.onclick); }); } catch (err) { console.error(err); alert('Failed to load child items. Please try again.'); } }); });
Optional CSS for Better UI
Add this to your stylesheet to make the treeview look cleaner:
.child-items { margin-left: 20px; display: none; } .child-items.loaded { display: block; } .expand-btn { background: none; border: none; cursor: pointer; padding: 0; }
Why Your Previous Approaches Didn't Work
- Server-side function calls in cshtml: Once the page renders, server-side code can't update the DOM directly—you need client-side JS to handle dynamic changes.
- RedirectToPage: This forces a full page reload, which ruins the smooth treeview experience we want.
内容的提问来源于stack exchange,提问作者로다현
相关产品推荐
相关产品推荐

