Лучший способ получить ссылку на главную страницу MVC 3 Razor
Когда я хочу, чтобы определенная ссылка на меню была активной на данной странице, я использую этот подход в Razor:
На макете мастера у меня есть эти проверки:
var active = ViewBag.Active;
const string ACTIVE_CLASS = "current";
if (active == "home")
{
ViewBag.ActiveHome = ACTIVE_CLASS;
}
if (active == "products")
{
ViewBag.ActiveProducts = ACTIVE_CLASS;
}
и др.
Меню html в макете макета:
<ul>
<li class="@ViewBag.ActiveHome"><a href="/">Home</a></li>
<li class="@ViewBag.ActiveProducts"><a href="@Url.Action("index", "products")">Products</a></li>
</ul>
При указании страницы макета для использования на другом представлении:
@{
ViewBag.Active = "home";
Layout = "~/Views/Shared/_Layout.cshtml";
}
Есть ли лучший подход для разделения активных ссылок, чем тот, который я сейчас использую?
Ответы
Ответ 1
Лучший подход заключается в использовании HTML-помощника:
using System.Web.Mvc;
using System.Web.Mvc.Html;
public static class MenuExtensions
{
public static MvcHtmlString MenuItem(
this HtmlHelper htmlHelper,
string text,
string action,
string controller
)
{
var li = new TagBuilder("li");
var routeData = htmlHelper.ViewContext.RouteData;
var currentAction = routeData.GetRequiredString("action");
var currentController = routeData.GetRequiredString("controller");
if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
{
li.AddCssClass("active");
}
li.InnerHtml = htmlHelper.ActionLink(text, action, controller).ToHtmlString();
return MvcHtmlString.Create(li.ToString());
}
}
а затем:
<ul>
@Html.MenuItem("Home", "Home", "Home")
@Html.MenuItem("Products", "Index", "Products")
</ul>
Для выполнения вышеуказанной работы вам понадобятся ваши взгляды, чтобы узнать ваше расширение: в Web.config в папке "Виды" добавьте <add namespace="yourNamespacehere.Helpers" />
внутри тега пространств имен. Затем создайте проект и закройте и снова откройте представление, которое вы добавляете.
тогда на основе текущего действия и контроллера хелпер добавит или не класс active
при создании якоря.
Ответ 2
Развернувшись на примере Дарина, здесь полный класс, который добавляет дополнительные дополнительные параметры для RouteValues и HtmlAttributes в помощнике. По сути, он ведет себя так же, как базовый ActionLink.
using System;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace MYNAMESPACE.Helpers {
public static class MenuExtensions {
public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper,
string text, string action,
string controller,
object routeValues = null,
object htmlAttributes = null) {
var li = new TagBuilder("li");
var routeData = htmlHelper.ViewContext.RouteData;
var currentAction = routeData.GetRequiredString("action");
var currentController = routeData.GetRequiredString("controller");
if (string.Equals(currentAction,
action,
StringComparison.OrdinalIgnoreCase) &&
string.Equals(currentController,
controller,
StringComparison.OrdinalIgnoreCase)) {
li.AddCssClass("active");
}
if (routeValues != null) {
li.InnerHtml = (htmlAttributes != null)
? htmlHelper.ActionLink(text,
action,
controller,
routeValues,
htmlAttributes).ToHtmlString()
: htmlHelper.ActionLink(text,
action,
controller,
routeValues).ToHtmlString();
}
else {
li.InnerHtml = htmlHelper.ActionLink(text,
action,
controller).ToHtmlString();
}
return MvcHtmlString.Create(li.ToString());
}
}
}
И в папке View web.config:
<system.web.webPages.razor>
<host ... />
<pages ... >
<namespaces>
...
...
<add namespace="MYNAMESPACE.Helpers" />
</namespaces>
</pages>
</system.web.webPages.razor>
Ответ 3
Используйте этот InnerHtml, если вы хотите включить форматирование HTML в свой текст;
li.InnerHtml = "<a href=\"" + new UrlHelper(htmlHelper.ViewContext.RequestContext).Action(action, controller).ToString() + "\">" + text + "</a>";
текст может быть "<b> Bold </b> Normal";
Ответ 4
Обновлено для RC2. Для тех, кто задается вопросом, как это сделать в MVC6/Asp.Net 5 - похоже, но тонко отличается. Теперь нет MvcHtmlString
, а RouteData
работает совершенно по-другому. Кроме того, теперь объект контекста должен быть IHtmlContent
, а не HtmlHelper
.
using System;
using Microsoft.AspNet.Mvc.Rendering;
public static class MenuExtensions
{
public static IHtmlContent MenuItem(
this IHtmlHelper htmlHelper,
string text,
string action,
string controller
)
{
var li = new TagBuilder("li") { TagRenderMode = TagRenderMode.Normal };
var routeData = htmlHelper.ViewContext.RouteData;
var currentAction = routeData.Values["action"].ToString();
var currentController = routeData.Values["controller"].ToString();
if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
{
li.AddCssClass("active");
}
li.InnerHtml.AppendHtml(htmlHelper.ActionLink(text, action, controller));
return li;
}
}
Ответ 5
Этот код отлично подойдет для меня, даже в новом проекте MVC5/Bootstrap Visual Studio 2013. Также обратите внимание, что вы можете изменить li.AddCssClass( "active" ); line, чтобы указать на пользовательский класс, если вы хотите оставить только активный класс Bootstrap. Я добавил один из них "activemenu" в файле Site.css проекта и сделал какие-то изменения в стиле навигации, которые я хотел там.
Линия в приведенном выше коде была просто изменена на это, чтобы заставить все это работать:
li.AddCssClass("activemenu");
В Site.css я добавил простой класс для своей цели:
.activemenu {
text-decoration: underline;
}
В качестве альтернативы вы можете изменить цвет фона и/или границу и т.д.
Ответ 6
здесь есть расширение для класса Darin для вставки html в текст ссылки, а не простой текст
using System;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace YourNameSpaceHere
{
public static class MenuExtensions
{
public static MvcHtmlString MenuItem(
this HtmlHelper htmlHelper,
string html,
string action,
string controller
)
{
var li = new TagBuilder("li");
var routeData = htmlHelper.ViewContext.RouteData;
var currentAction = routeData.GetRequiredString("action");
var currentController = routeData.GetRequiredString("controller");
if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
{
li.AddCssClass("active");
}
//generate a unique id for the holder and convert it to string
string holder = Guid.NewGuid().ToString();
string anchor = htmlHelper.ActionLink(holder, action, controller).ToHtmlString();
//replace the holder string with the html
li.InnerHtml = anchor.Replace(holder, html);
return MvcHtmlString.Create(li.ToString());
}
}
}
и используйте его следующим образом:
<ul>
@Html.MenuItem("<span class'ClassName'>Home</span>", "Home", "Home")
</ul>