Blazor递归分类菜单问题:仅展开选中分类的子菜单
解决Blazor递归菜单仅展开选中分类的问题
问题根源
你现在的问题出在用了全局的展开/折叠状态变量,导致点击任何分类都会触发所有菜单同步展开/折叠。递归菜单的核心是每个分类项必须维护自己独立的展开状态,不能共用同一个变量。
具体解决方案
1. 给分类添加独立的展开状态
有两种实现方式,选适合你的:
方案A:直接给分类模型加属性(最简单)
如果你的分类模型(比如Category)可以修改,新增一个IsExpanded属性:
public class Category { public int Id { get; set; } public string Name { get; set; } public List<Category> SubCategories { get; set; } = new(); // 每个分类自己的展开状态,默认折叠 public bool IsExpanded { get; set; } = false; }
方案B:用字典存储状态(不修改原有模型)
如果不想改动后端返回的模型,就在组件里用字典记录每个分类的展开状态:
// 键是分类ID,值是展开状态 private Dictionary<int, bool> _expandedStates = new(); protected override void OnInitialized() { // 初始化所有分类为折叠状态,假设你的分类列表是Categories InitExpandedStates(Categories); } private void InitExpandedStates(List<Category> categories) { foreach (var cat in categories) { if (!_expandedStates.ContainsKey(cat.Id)) _expandedStates[cat.Id] = false; // 递归初始化子分类 if (cat.SubCategories?.Any() == true) InitExpandedStates(cat.SubCategories); } }
2. 修改递归渲染逻辑
用递归组件实现(推荐,代码更清晰)
新建一个CategoryItem.razor组件,专门渲染单个分类:
@* 接收当前要渲染的分类 *@ [Parameter] public Category CurrentCat { get; set; } <div class="category-item"> <button @onclick="ToggleExpand"> @(CurrentCat.IsExpanded ? "▼" : "▶") @CurrentCat.Name </button> @* 只有当前分类展开且有子分类时,才渲染子菜单 *@ @if (CurrentCat.IsExpanded && CurrentCat.SubCategories.Any()) { <div style="padding-left: 20px;"> @foreach (var subCat in CurrentCat.SubCategories) { <CategoryItem CurrentCat="subCat" /> } </div> } </div> @code { private void ToggleExpand() { // 切换当前分类的展开状态 CurrentCat.IsExpanded = !CurrentCat.IsExpanded; } }
然后在父组件里调用这个递归组件:
<div class="category-container"> @foreach (var cat in Categories) { <CategoryItem CurrentCat="cat" /> } </div> @code { private List<Category> Categories { get; set; } // 从后端加载分类数据的逻辑 protected override async Task OnInitializedAsync() { Categories = await YourBackendService.GetAllCategories(); } }
用字典状态的渲染方式(不用单独组件)
如果不想新建组件,直接在父组件里递归渲染:
@foreach (var cat in Categories) { <RenderCategory Cat="cat" /> } @code { private void RenderCategory(Category cat) { <div class="category-item"> <button @onclick="() => ToggleCat(cat.Id)"> @(_expandedStates[cat.Id] ? "▼" : "▶") @cat.Name </button> @if (_expandedStates[cat.Id] && cat.SubCategories.Any()) { <div style="padding-left: 20px;"> @foreach (var subCat in cat.SubCategories) { RenderCategory(subCat); } </div> } </div> } private void ToggleCat(int catId) { _expandedStates[catId] = !_expandedStates[catId]; } }
常见坑点排查
- 绝对不要用全局的
bool IsExpanded变量控制所有菜单,必须给每个分类单独分配状态。 - 递归渲染时,子分类的状态要完全独立,不要继承父级的状态变量。
- 如果用字典存储状态,确保每个分类的ID是唯一的,避免不同分类共享同一个状态。
内容的提问来源于stack exchange,提问作者MangoSamurai
相关产品推荐
相关产品推荐

