MVCのbootstrap navbarに「アクティブな」クラスを追加しようとしていますが、次のように記述した場合、アクティブなクラスが表示されません。
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home", null, new {@class="active"})</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
これは、正しくフォーマットされたクラスのように見えますが、機能しません:
<a class="active" href="/">Home</a>
Bootstrapのドキュメントでは、「a」タグをnavbarで使用すべきではないと記載されていますが、Html.ActionLinkにクラスを追加する正しい方法は上記のとおりです。これを行うことができる別の(整頓された)方法はありますか?
Bootstrapでは、active
クラスを<li>
ではなく、<a>
要素に適用する必要があります。最初の例を参照してください: http://getbootstrap.com/components/#navbar
アクティブかどうかに基づいてUIスタイルを処理する方法は、ASP.NET MVCのActionLink
ヘルパーとは関係ありません。これは、Bootstrapフレームワークの構築方法に従う適切なソリューションです。
<ul class="nav navbar-nav">
<li class="active">@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
編集:
メニューを複数のページで再利用する可能性が高いため、メニューを複数回コピーして手動で行うのではなく、現在のページに基づいて選択したクラスを自動的に適用する方法が賢明です。
最も簡単な方法は、ViewContext.RouteData
に含まれる値、つまりAction
およびController
の値を単純に使用することです。次のようなものを使用して、現在持っているものの上に構築できます。
<ul class="nav navbar-nav">
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
それはコードではきれいではありませんが、仕事が完了し、必要に応じてメニューを部分ビューに抽出することができます。これをはるかにクリーンな方法で行う方法がありますが、始めたばかりなので、そのままにしておきます。 ASP.NET MVCを学ぶのは幸運です!
後期編集:
この質問は少しトラフィックが増えているように思えるので、HtmlHelper
拡張機能を使用してよりエレガントなソリューションを投入すると思いました。
編集03-24-2015:選択した動作をトリガーする複数のアクションとコントローラー、および子アクションの部分ビューからメソッドが呼び出されたときの処理を可能にするために、このメソッドを書き直さなければなりませんでした、更新を共有すると思います!
public static string IsSelected(this HtmlHelper html, string controllers = "", string actions = "", string cssClass = "selected")
{
ViewContext viewContext = html.ViewContext;
bool isChildAction = viewContext.Controller.ControllerContext.IsChildAction;
if (isChildAction)
viewContext = html.ViewContext.ParentActionViewContext;
RouteValueDictionary routeValues = viewContext.RouteData.Values;
string currentAction = routeValues["action"].ToString();
string currentController = routeValues["controller"].ToString();
if (String.IsNullOrEmpty(actions))
actions = currentAction;
if (String.IsNullOrEmpty(controllers))
controllers = currentController;
string[] acceptedActions = actions.Trim().Split(',').Distinct().ToArray();
string[] acceptedControllers = controllers.Trim().Split(',').Distinct().ToArray();
return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
cssClass : String.Empty;
}
。NET Coreで動作:
public static string IsSelected(this IHtmlHelper htmlHelper, string controllers, string actions, string cssClass = "selected")
{
string currentAction = htmlHelper.ViewContext.RouteData.Values["action"] as string;
string currentController = htmlHelper.ViewContext.RouteData.Values["controller"] as string;
IEnumerable<string> acceptedActions = (actions ?? currentAction).Split(',');
IEnumerable<string> acceptedControllers = (controllers ?? currentController).Split(',');
return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
cssClass : String.Empty;
}
サンプル使用法:
<ul>
<li class="@Html.IsSelected(actions: "Home", controllers: "Default")">
<a href="@Url.Action("Home", "Default")">Home</a>
</li>
<li class="@Html.IsSelected(actions: "List,Detail", controllers: "Default")">
<a href="@Url.Action("List", "Default")">List</a>
</li>
</ul>
拡張:
public static MvcHtmlString LiActionLink(this HtmlHelper html, string text, string action, string controller)
{
var context = html.ViewContext;
if (context.Controller.ControllerContext.IsChildAction)
context = html.ViewContext.ParentActionViewContext;
var routeValues = context.RouteData.Values;
var currentAction = routeValues["action"].ToString();
var currentController = routeValues["controller"].ToString();
var str = String.Format("<li role=\"presentation\"{0}>{1}</li>",
currentAction.Equals(action, StringComparison.InvariantCulture) &&
currentController.Equals(controller, StringComparison.InvariantCulture) ?
" class=\"active\"" :
String.Empty, html.ActionLink(text, action, controller).ToHtmlString()
);
return new MvcHtmlString(str);
}
使用法:
<ul class="nav navbar-nav">
@Html.LiActionLink("About", "About", "Home")
@Html.LiActionLink("Contact", "Contact", "Home")
</ul>
Asp.net mvcにビューバッグパラメーターを追加することで、これを実行しようとしました。ここで私がしたこと
各ページにViewBag.Current = "Scheduler";
likeパラメーターを追加しました
レイアウトページ
<ul class="nav navbar-nav">
<li class="@(ViewBag.Current == "Scheduler" ? "active" : "") "><a href="@Url.Action("Index","Scheduler")" target="_self">Scheduler</a></li>
</ul>
これで私の問題が解決しました。
少し遅れることがあります。しかし、これが役立つことを願っています。
public static class Utilities
{
public static string IsActive(this HtmlHelper html,
string control,
string action)
{
var routeData = html.ViewContext.RouteData;
var routeAction = (string)routeData.Values["action"];
var routeControl = (string)routeData.Values["controller"];
// both must match
var returnActive = control == routeControl &&
action == routeAction;
return returnActive ? "active" : "";
}
}
そして、次のような使用法:
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class='@Html.IsActive("Home", "Index")'>
@Html.ActionLink("Home", "Index", "Home")
</li>
<li class='@Html.IsActive("Home", "About")'>
@Html.ActionLink("About", "About", "Home")
</li>
<li class='@Html.IsActive("Home", "Contact")'>
@Html.ActionLink("Contact", "Contact", "Home")
</li>
</ul>
</div>
http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html から参照を得ました
私はこの質問が古いことを知っていますが、ここに私の声を追加したいと思います。ビューのコントローラーへのリンクがアクティブかどうかの知識を残すことは良い考えだと思います。
コントローラーアクションの各ビューに一意の値を設定するだけです。たとえば、ホームページリンクをアクティブにしたい場合は、次のようにします。
public ActionResult Index()
{
ViewBag.Title = "Home";
ViewBag.Home = "class = active";
return View();
}
それから私の見解では、私はこのような何かを書きます:
<li @ViewBag.Home>@Html.ActionLink("Home", "Index", "Home", null, new { title = "Go home" })</li>
別のページ、たとえばプログラムに移動すると、ViewBag.Homeは存在しません(代わりにViewBag.Programsが存在します)。したがって、何もレンダリングされず、class = ""でさえレンダリングされません。これは保守性と清潔さの両方でよりクリーンだと思います。私は常に、できる限りロジックをビューから外したいと思う傾向があります。
このソリューションは、Asp.net MCV 5では簡単です。
Utilitarios.cs
などの静的クラスを作成します。
クラス内で静的メソッドを作成します。
public static string IsLinkActive(this UrlHelper url, string action, string controller)
{
if (url.RequestContext.RouteData.Values["controller"].ToString() == controller &&
url.RequestContext.RouteData.Values["action"].ToString() == action)
{
return "active";
}
return "";
}
こう呼ぶ
<ul class="sidebar-menu" data-widget="tree">
<li class="header">HEADER</li>
<li class="@Url.IsLinkActive("Index", "Home")">
<a href="@Url.Action("Index", "Home")"><i class="fa fa-link"></i> <span>Home</span></a>
</li>
<li class="@Url.IsLinkActive("About", "Home")">
<a href="@Url.Action("About", "Home")"><i class="fa fa-link"></i><span>About</span></a>
</li>
</ul>
あなたはこれを試すことができます:私の場合、ロールベースのアクセスに基づいてデータベースからメニューをロードしています、ビューに基づいてアクティブにするメニューをすべてのビューにコードを書いてください。
<script type="text/javascript">
$(document).ready(function () {
$('li.active active-menu').removeClass('active active-menu');
$('a[href="/MgtCustomer/Index"]').closest('li').addClass('active active-menu');
});
</script>
ラムダ関数で可能です
@{
string controllerAction = ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString();
Func<string, string> IsSelected= x => x==controllerAction ? "active" : "";
}
その後の使用
@Html.ActionLink("Inicio", "Index", "Home", new { area = "" }, new { @class = IsSelected("HomeIndex")})
Damithが投稿した内容を考慮すると、Viewbag.Titleでアクティブに限定できると思います(ベストプラクティスは、コンテンツページに_Layout.cshtml
ページにリンクバーを保持できるようにすることです)。また、サブメニュー項目を使用している場合も正常に機能することに注意してください。
<li class="has-sub @(ViewBag.Title == "Dashboard 1" || ViewBag.Title == "Dashboard 2" ? "active" : "" )">
<a href="javascript:;">
<b class="caret"></b>
<i class="fa fa-th-large"></i>
<span>Dashboard</span>
</a>
<ul class="sub-menu">
<li class="@(ViewBag.Title == "Dashboard 1" ? "active" : "")"><a href="index.html">Dashboard v1</a></li>
<li class="@(ViewBag.Title == "Dashboard 2" ? "active" : "")"><a href="index_v2.html">Dashboard v2</a></li>
</ul>
</li>
dom's"not pretty" answer を変更し、よりugくしました。時々、2つのコントローラーに競合するアクション名(つまり、インデックス)があるため、これを行います。
<ul class="nav navbar-nav">
<li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "HomeIndex" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "AboutIndex" ? "active" : "")">@Html.ActionLink("About", "Index", "About")</li>
<li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "ContactHome" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
'.ToString'を追加して、ASP.NET MVCでの比較を改善します
<ul class="nav navbar-nav">
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
-
MvcHandler自体から取得できるRequestContextからUrlHelper
を作成することもできます。したがって、このロジックを次の方法でRazorテンプレートに保持したい人が役に立つと思います。
AppCode
という名前のフォルダーを作成します。HtmlHelpers.cshtml
という名前のファイルを作成しますそこにヘルパーを作成します。
@helper MenuItem(string action, string controller)
{
var mvcHandler = Context.CurrentHandler as MvcHandler;
if (mvcHandler != null)
{
var url = new UrlHelper(mvcHandler.RequestContext);
var routeData = mvcHandler.RequestContext.RouteData;
var currentAction = routeData.Values["action"].ToString();
var currentController = routeData.Values["controller"].ToString();
var isCurrent = string.Equals(currentAction, action, StringComparison.InvariantCultureIgnoreCase) &&
string.Equals(currentController, controller, StringComparison.InvariantCultureIgnoreCase);
<div class="@(isCurrent ? "active" : "")">
<div>@url.Action(action, controller)</div>
</div>
}
}
次に、次のようにビューで使用できます。
@HtmlHelpers.MenuItem("Default", "Home")
それが誰かに役立つことを願っています。
私も解決策を探していましたが、jQueryはほとんど役に立ちました。最初に、<li>
要素に「id」を与える必要があります。
<li id="listguides"><a href='/Guides/List'>List Guides</a></li>
レイアウトページでこれを実行した後、ビューで「選択」する必要がある<li>
要素をjQueryに伝えることができます。
@section Scripts{
<script type="text/javascript">
$('#listguides').addClass('selected');
</script>
}
注:セクションを追加するには、レイアウトページの</body>
タグの直前に@RenderSection("scripts", required: false)
が必要です。
@dombenoitによる答えは機能します。それは維持するためにいくつかのコードを紹介しますが。次の構文を確認してください。
using (var nav = Html.Bootstrap().Begin(new Nav().Style(NavType.NavBar).SetLinksActiveByControllerAndAction()))
{
@nav.ActionLink("Link 1", "action1")
@nav.ActionLink("Link 2", "action2")
@nav.Link("External Link", "#")
}
.SetLinksActiveByControllerAndAction()
メソッドの使用に注意してください。
この構文が可能になる理由について疑問がある場合は、 TwitterBootstrapMVC を確認してください。
この問題は私たちの中にはよくある問題であることに気づいたので、nugetパッケージを使用して独自のソリューションを公開しました。以下に、その仕組みを確認できます。これが役に立つことを願っています。
注:このnugetパッケージは私の最初のパッケージです。間違いを見つけたら、フィードバックをお願いします。ありがとう。
パッケージのインストールまたはソースコードのダウンロードとプロジェクトの追加
-Install-Package Betalgo.MvcMenuNavigator
ページを列挙に追加します
public enum HeaderTop
{
Dashboard,
Product
}
public enum HeaderSub
{
Index
}
コントローラーまたはアクションの一番上にフィルターを配置
[MenuNavigator(HeaderTop.Product, HeaderSub.Index)]
public class ProductsController : Controller
{
public async Task<ActionResult> Index()
{
return View();
}
[MenuNavigator(HeaderTop.Dashboard, HeaderSub.Index)]
public async Task<ActionResult> Dashboard()
{
return View();
}
}
そして、このようにヘッダーレイアウトで使用します
@{
var headerTop = (HeaderTop?)MenuNavigatorPageDataNavigatorPageData.HeaderTop;
var headerSub = (HeaderSub?)MenuNavigatorPageDataNavigatorPageData.HeaderSub;
}
<div class="nav-collapse collapse navbar-collapse navbar-responsive-collapse">
<ul class="nav navbar-nav">
<li class="@(headerTop==HeaderTop.Dashboard?"active selected open":"")">
<a href="@Url.Action("Index","Home")">Dashboard</a>
</li>
<li class="@(headerTop==HeaderTop.Product?"active selected open":"")">
<a href="@Url.Action("Index", "Products")">Products</a>
</li>
</ul>
ここでは、選択したメニューを「アクティブ」にするための、よりクリーンで小さなコードがあると思います。
<ul class="navbar-nav mr-auto">
<li class="nav-item @Html.IfSelected("Index")">
<a class="nav-link" href="@Url.Action("Index", "Home")">Home</a>
</li>
<li class="nav-item @Html.IfSelected("Controls")">
<a class="nav-link" href="@Url.Action("Controls", "Home")">MVC Controls</a>
</li>
<li class="nav-item @Html.IfSelected("About")">
<a class="nav-link" href="@Url.Action("About", "Home")">About</a>
</li>
</ul>
public static string IfSelected(this HtmlHelper html, string action)
{
return html
.ViewContext
.RouteData
.Values["action"]
.ToString() == action
? " active"
: "";
}
これは私がしました:
メニューの部分ビューでヘルパーを作成
@helper RouterLink(string action, string controller)
{
var IsActive = ViewContext.RouteData.Values["Controller"].ToString() == controller && ViewContext.RouteData.Values["Action"].ToString() == action;
<text>href="@Url.Action(action, controller)"</text>if (IsActive){ <text>class="active"</text>}
}
その後、このようにアンカータグで使用しました:
<li><a @RouterLink("Index","Home")>Home</a></li>
アプリケーションには領域がありませんでしたが、ヘルパー関数の別の変数として含めることもできます。そして、アクティブなクラスをビューのアンカータグに渡すようにしました。ただし、li
もこのように構成できます。
リンクを囲む<li>
ではなく、リンク自体に「アクティブな」クラスを追加したい人のためにHtmlHelper
メソッドを追加するActiveActionLink
拡張を作成しました。
public static class LinkExtensions
{
public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
{
const string activeClassName = "active";
var routeData = html.ViewContext.RouteData;
var routeAction = (string)routeData.Values["action"];
var routeController = (string)routeData.Values["controller"];
var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);
if (active)
{
var @class = (string)htmlAttributes["class"];
htmlAttributes["class"] = string.IsNullOrEmpty(@class)
? activeClassName
: @class + " active";
}
var link = html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);
return link;
}
}
使用法は次のとおりです。
@Html.ActiveActionLink("Home", "Index", "Home", new { area = "" }, new { @class = "nav-item nav-link" })
これがお役に立てば幸いです。メニューは次のとおりです。
<ul class="nav navbar-nav">
<li><a href="@Url.Action("Index", "Home")" class="@IsMenuSelected("Index","Home", "active")">Home</a></li>
<li><a href="@Url.Action("About", "Home")" class="@IsMenuSelected("About", "Home", "active")">About</a></li>
<li><a href="@Url.Action("Contact", "Home")" class="@IsMenuSelected("Contact", "Home", "active")">Contact</a></li>
</ul>
そして、htmlタグの下にMVCヘルパー関数を追加します。
@helper IsMenuSelected(string actionName, string controllerName, string className)
{
var conname = ViewContext.RouteData.Values["controller"].ToString().ToLower();
var actname = ViewContext.RouteData.Values["action"].ToString().ToLower();
if (conname == controllerName.ToLower() && actname == actionName.ToLower())
{
@className;
}
}
http://questionbox.in/add-active-class-menu-link-html-actionlink-asp-net-mvc/ からの回答を参照しました
Domの答えの最初の部分に基づいたこのソリューションを提案したいと思います。
最初に2つの変数「action」と「controller」を定義し、それらを使用してアクティブリンクを決定します。
{ string controller = ViewContext.RouteData.Values["Controller"].ToString();
string action = ViewContext.RouteData.Values["Action"].ToString();}
その後:
<ul class="nav navbar-nav">
<li class="@((controller == "Home" && action == "Index") ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@((controller == "Home" && action == "About") ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
<li class="@((controller == "Home" && action == "Contact") ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
今では見栄えが良くなり、より複雑なソリューションは不要になりました。
それがまったく表示されていない場合、理由は2つの@記号が必要だからです:
@@class
しかし、「a」タグではなく「li」タグにアクティブなクラスが必要になると思います。 bootstrap docs( http://getbootstrap.com/components/#navbar-default ):
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#">Profile</a></li>
<li><a href="#">Messages</a></li>
</ul>
したがって、コードは次のようになります。
<ul class="nav navbar-nav">
<li class="active">@Html.ActionLink("Home", "Index", "Home", null)</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
この問題に対する私の解決策は
<li class="@(Context.Request.Path.Value.ToLower().Contains("about") ? "active " : "" ) nav-item">
<a class="nav-link" asp-area="" asp-controller="Home" asp-action="About">About</a>
</li>
より良い方法は、リンクと比較する現在のパスを返すためのHtml拡張メソッドを追加することです
上記の回答を組み合わせて、解決策を作成しました。
そう..
まず、剃刀ブロックで、コントローラーの名前の値とユーザーによって呼び出されるアクションを含む1つの文字列変数を作成します。
@{
string controllerAction = ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString();
}
次に、HTMLとRazorコードの組み合わせを使用します。
<ul class="nav navbar-nav">
<li class="@(controllerAction == "HomeIndex" ? "active" : "" )">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(controllerAction == "AboutIndex" ? "active" : "" )">@Html.ActionLink("About", "Index", "About")</li>
<li class="@(controllerAction == "HomeContact" ? "active" : "" )">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
コントローラ名とアクション名を取得するために毎回「ViewContext.RouteData.Values」にアクセスする必要がないので、これは良いと思います。