記事詳細


投稿日
2026年09月28日19時22分
タイトル

ASP.NET Core MVC: MVCアプリでメニューを階層ドロップダウンで表示する方法を教えてください。

内容

了解です。
前回の階層ドロップダウンメニュー実装例を、さらに 実務向けの拡張版 に改良します。
今回は Bootstrap 5 をベースに、多階層対応 + アクティブ強調 + アイコン対応 + ホバー展開 を組み込みます。

1. モデル(自己参照型 + アイコン対応)

Csharp
// Models/MenuItem.cs using System.Collections.Generic; namespace YourApp.Models { public class MenuItem { public int Id { get; set; } public string Title { get; set; } public string Url { get; set; } public int? ParentId { get; set; } public List<MenuItem> Children { get; set; } = new(); // 表示制御用 public bool IsActive { get; set; } // アイコン(Font Awesomeなど) public string IconClass { get; set; } } }

2. コントローラー(階層構築 + アクティブ判定)

Csharp
// Controllers/MenuController.cs using Microsoft.AspNetCore.Mvc; using YourApp.Models; using System.Collections.Generic; using System.Linq; namespace YourApp.Controllers { public class MenuController : Controller { public IActionResult Index() { var flatMenu = new List<MenuItem> { new MenuItem { Id = 1, Title = "ホーム", Url = "/", IconClass = "fa fa-home" }, new MenuItem { Id = 2, Title = "製品", Url = "/products", IconClass = "fa fa-box" }, new MenuItem { Id = 3, Title = "サービス", Url = "/services", IconClass = "fa fa-cogs" }, new MenuItem { Id = 4, Title = "製品A", Url = "/products/a", ParentId = 2 }, new MenuItem { Id = 5, Title = "製品B", Url = "/products/b", ParentId = 2 }, new MenuItem { Id = 6, Title = "サービスX", Url = "/services/x", ParentId = 3 }, new MenuItem { Id = 7, Title = "サービスY", Url = "/services/y", ParentId = 3 }, new MenuItem { Id = 8, Title = "製品B詳細", Url = "/products/b/detail", ParentId = 5 } }; var menuTree = BuildTree(flatMenu); MarkActiveMenu(menuTree, HttpContext.Request.Path); return View(menuTree); } private List<MenuItem> BuildTree(List<MenuItem> items) { var lookup = items.ToDictionary(x => x.Id); var roots = new List<MenuItem>(); foreach (var item in items) { if (item.ParentId.HasValue && lookup.ContainsKey(item.ParentId.Value)) { lookup[item.ParentId.Value].Children.Add(item); } else { roots.Add(item); } } return roots; } private bool MarkActiveMenu(List<MenuItem> menuItems, string currentPath) { bool found = false; foreach (var item in menuItems) { if (item.Url?.Equals(currentPath, System.StringComparison.OrdinalIgnoreCase) == true) { item.IsActive = true; found = true; } else if (item.Children.Any() && MarkActiveMenu(item.Children, currentPath)) { item.IsActive = true; found = true; } } return found; } } }

3. メインビュー(Bootstrap + 多階層CSS + ホバー展開)

Html
@model List<YourApp.Models.MenuItem> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <style> /* 多階層ドロップダウン対応 */ .dropdown-submenu { position: relative; } .dropdown-submenu > .dropdown-menu { top: 0; left: 100%; margin-top: -0.125rem; } /* アクティブ強調 */ .nav-link.active, .dropdown-item.active { background-color: #0d6efd; color: #fff !important; } /* ホバー展開 */ .navbar-nav li:hover > .dropdown-menu { display: block; } </style> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container-fluid"> <ul class="navbar-nav"> @foreach (var item in Model) { @Html.Partial("_MenuItemPartial", item) } </ul> </div> </nav> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>

4. 再帰的部分ビュー(アイコン + アクティブクラス)

Html
@model YourApp.Models.MenuItem @if (Model.Children.Any()) { <li class="nav-item dropdown @(Model.ParentId != null ? "dropdown-submenu" : "")"> <a class="nav-link dropdown-toggle @(Model.IsActive ? "active" : "")" href="@Model.Url" role="button" data-bs-toggle="dropdown" aria-expanded="false"> @if (!string.IsNullOrEmpty(Model.IconClass)) { <i class="@Model.IconClass"></i> } @Model.Title </a> <ul class="dropdown-menu"> @foreach (var child in Model.Children) { @Html.Partial("_MenuItemPartial", child) } </ul> </li> } else { <li> <a class="dropdown-item @(Model.IsActive ? "active" : "")" href="@Model.Url"> @if (!string.IsNullOrEmpty(Model.IconClass)) { <i class="@Model.IconClass"></i> } @Model.Title </a> </li> }

改良点

  1. アイコン対応
    Font Awesome を利用してメニューにアイコンを追加。
  2. ホバー展開
    マウスオーバーでサブメニューが開くようにCSSを追加。
  3. 多階層対応
    .dropdown-submenu を利用して右側に階層表示。
  4. アクティブ強調
    現在ページとその親階層を自動的にハイライト。

この改良版は、多階層 + アイコン + ホバー展開 + アクティブ強調 を兼ね備えており、
そのまま _Layout.cshtml に組み込めば全ページ共通メニューとして利用できます。

次はこのコードを DB連動 + 管理画面から編集可能 に拡張したバージョンも作成できますが、
それを作りますか?
そうすれば運用時にコードを触らずにメニューを更新できます。

Powered by Froala Editor

添付画像

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