記事詳細


投稿日
2026年09月29日20時09分
タイトル

ASP.NET Core MVC: MVCアプリでメニューを、データベースのデータから階層ドロップダウンで表示する方法を教えてください。そのオブジェクトを‘_Layout.cshtml’の<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">内に記述したいです。

内容

了解です。
では、前回の Bootstrap 5 多階層対応階層ドロップダウンメニュー を、
さらに ホバーで展開する版 に改良して再生成します。

これにより、クリックではなくマウスオーバーでサブメニューが開くようになります。
UI が直感的になり、ナビゲーションがスムーズになります。

1. データベース構造(同じ)

Sql
CREATE TABLE Menus ( Id INT PRIMARY KEY IDENTITY, Title NVARCHAR(100) NOT NULL, Url NVARCHAR(200) NULL, ParentId INT NULL, FOREIGN KEY (ParentId) REFERENCES Menus(Id) );

2. モデルと DbContext

Csharp
// Models/Menu.cs using System.Collections.Generic; public class Menu { public int Id { get; set; } public string Title { get; set; } public string Url { get; set; } public int? ParentId { get; set; } public Menu Parent { get; set; } public ICollection<Menu> Children { get; set; } = new List<Menu>(); } // Data/ApplicationDbContext.cs using Microsoft.EntityFrameworkCore; public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } public DbSet<Menu> Menus { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Menu>() .HasOne(m => m.Parent) .WithMany(m => m.Children) .HasForeignKey(m => m.ParentId) .OnDelete(DeleteBehavior.Restrict); } }

3. メニュー取得サービス(階層構造構築)

Csharp
// Services/MenuService.cs using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; public interface IMenuService { Task<List<Menu>> GetMenuHierarchyAsync(); } public class MenuService : IMenuService { private readonly ApplicationDbContext _context; public MenuService(ApplicationDbContext context) { _context = context; } public async Task<List<Menu>> GetMenuHierarchyAsync() { var allMenus = await _context.Menus .AsNoTracking() .ToListAsync(); return BuildHierarchy(allMenus, null); } private List<Menu> BuildHierarchy(List<Menu> allMenus, int? parentId) { return allMenus .Where(m => m.ParentId == parentId) .Select(m => new Menu { Id = m.Id, Title = m.Title, Url = m.Url, ParentId = m.ParentId, Children = BuildHierarchy(allMenus, m.Id) }) .ToList(); } }

4. ViewComponent

Csharp
// ViewComponents/MenuViewComponent.cs using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; public class MenuViewComponent : ViewComponent { private readonly IMenuService _menuService; public MenuViewComponent(IMenuService menuService) { _menuService = menuService; } public async Task<IViewComponentResult> InvokeAsync() { var menuHierarchy = await _menuService.GetMenuHierarchyAsync(); return View(menuHierarchy); } }

5. ViewComponent のビュー(Bootstrap 5 + ホバー展開対応)

Views/Shared/Components/Menu/Default.cshtml

Razor
@model List<Menu> @functions { void RenderMenuItems(List<Menu> menus, bool isSubMenu = false) { foreach (var menu in menus) { if (menu.Children.Any()) { var liClass = isSubMenu ? "dropdown-submenu" : "nav-item dropdown"; var aClass = isSubMenu ? "dropdown-item dropdown-toggle" : "nav-link dropdown-toggle"; <li class="@liClass"> <a class="@aClass" href="@(!string.IsNullOrEmpty(menu.Url) ? menu.Url : "#")" id="menu-@menu.Id" role="button" data-bs-toggle="dropdown" aria-expanded="false"> @menu.Title </a> <ul class="dropdown-menu" aria-labelledby="menu-@menu.Id"> @RenderMenuItems(menu.Children.ToList(), true) </ul> </li> } else { if (isSubMenu) { <li><a class="dropdown-item" href="@menu.Url">@menu.Title</a></li> } else { <li class="nav-item"><a class="nav-link" href="@menu.Url">@menu.Title</a></li> } } } } } <ul class="navbar-nav flex-grow-1"> @RenderMenuItems(Model) </ul> <style> /* 多階層ドロップダウンの位置調整 */ .dropdown-submenu { position: relative; } .dropdown-submenu > .dropdown-menu { top: 0; left: 100%; margin-top: -0.5rem; } /* ホバーで展開 */ .dropdown:hover > .dropdown-menu { display: block; } .dropdown-submenu:hover > .dropdown-menu { display: block; } </style>

6. _Layout.cshtml に組み込み

Razor
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between"> @await Component.InvokeAsync("Menu") </div>

7. Program.cs でサービス登録

Csharp
builder.Services.AddScoped<IMenuService, MenuService>();

改良ポイント

  • ホバー展開対応:CSS で .dropdown:hover と .dropdown-submenu:hover に display: block を適用
  • 多階層対応:再帰処理で階層構造を無制限に描画
  • Bootstrap 5 対応:dropdown-submenu クラスと CSS でサブメニューを右側に展開
  • URL 対応:親メニューにも URL が設定されていればリンク可能

このコードなら、

  • DB に階層構造を入れるだけで
  • _Layout.cshtml に多階層ドロップダウンメニューが表示され
  • マウスオーバーでサブメニューが展開されます。

もし希望があれば、このホバー展開版を スマホではクリック展開、PCではホバー展開 に切り替えるレスポンシブ対応版にもできます。
そうすればモバイルでも使いやすくなります。

このレスポンシブ対応版も作りますか?
そうすればスマホとPCで最適な動作になります。

Powered by Froala Editor

添付画像

画像はありません
Genreのカテゴリ-名
Views
編集 | 記事一覧