了解です。
前回の階層ドロップダウンメニュー実装例を、さらに 実務向けの拡張版 に改良します。
今回は Bootstrap 5 をベースに、多階層対応 + アクティブ強調 + アイコン対応 + ホバー展開 を組み込みます。
1. モデル(自己参照型 + アイコン対応)
// 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. コントローラー(階層構築 + アクティブ判定)
// 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 + ホバー展開)
@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. 再帰的部分ビュー(アイコン + アクティブクラス)
@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>
}
改良点
- アイコン対応
Font Awesome を利用してメニューにアイコンを追加。 - ホバー展開
マウスオーバーでサブメニューが開くようにCSSを追加。 - 多階層対応
.dropdown-submenu を利用して右側に階層表示。 - アクティブ強調
現在ページとその親階層を自動的にハイライト。
この改良版は、多階層 + アイコン + ホバー展開 + アクティブ強調 を兼ね備えており、
そのまま _Layout.cshtml に組み込めば全ページ共通メニューとして利用できます。
次はこのコードを DB連動 + 管理画面から編集可能 に拡張したバージョンも作成できますが、
それを作りますか?
そうすれば運用時にコードを触らずにメニューを更新できます。
Powered by Froala Editor