2

メニュー項目の HTML ヘルパー メソッドを作成する例をいくつか見てきました。active

**Summary:**簡単に言えば、MVC プロジェクトでは、Twitter Bootstrap を使用して、子が選択されたときに折りたたみ可能なメニューの開いた状態を保持しようとしています。

active open子が選択されている場合、親の css (選択された項目) を含める必要がある折りたたみ可能なメニューを使用しています。これにより、メニューが正しい場所で開かれます。別の HTML ヘルパーを使用すると、アクティブなアイテムは既に に設定されていactiveます。

メニューの HTML:

    <div id="sidebar">
        <ul>
            <li class="active"><a href="dashboard.html"><i class="icon-home"></i> <span>Dashboard</span></a></li>
            <li class="submenu">
                <a href="#"><i class="icon-beaker"></i> <span>UI Lab</span> <i class="arrow icon-chevron-right"></i></a>
                <ul>
                    <li><a href="interface.html">Interface Elements</a></li>
                    <li><a href="jquery-ui.html">jQuery UI</a></li>
                    <li><a href="buttons.html">Buttons &amp; icons</a></li>
                </ul>
            </li>
            <li class="submenu">
                <a href="#"><i class="icon-th-list"></i> <span>Form elements</span> <i class="arrow icon-chevron-right"></i></a>
                <ul>
                    <li><a href="form-common.html">Common elements</a></li>
                    <li><a href="form-validation.html">Validation</a></li>
                    <li><a href="form-wizard.html">Wizard</a></li>
                </ul>
            </li>
            <li><a href="tables.html"><i class="icon-th"></i> <span>Tables</span></a></li>
            <li><a href="grid.html"><i class="icon-th-list"></i> <span>Grid Layout</span></a></li>
            <li class="submenu">
                <a href="#"><i class="icon-file"></i> <span>Sample pages</span> <i class="arrow icon-chevron-right"></i></a>
                <ul>
                    <li><a href="invoice.html">Invoice</a></li>
                    <li><a href="chat.html">Support chat</a></li>
                    <li><a href="calendar.html">Calendar</a></li>
                    <li><a href="gallery.html">Gallery</a></li>
                    <li><a href="messages.html">Messages</a></li>
                </ul>
            </li>
            <li>
                <a href="charts.html"><i class="icon-signal"></i> <span>Charts &amp; graphs</span></a>
            </li>
            <li>
                <a href="widgets.html"><i class="icon-inbox"></i> <span>Widgets</span></a>
            </li>
        </ul>

    </div>

アイテムのヘルパー メソッドは次のとおりです。

    public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper,
        string text,
        string action,
        string controller,
        string iconClass)
    {
        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");
        }

        var i = new TagBuilder("i");
        i.AddCssClass(iconClass);

        var basePath = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);

        //li.InnerHtml = htmlHelper.ActionLink("<i>something</i>" + text, action, controller).ToHtmlString();
        li.InnerHtml = htmlHelper.Raw(string.Format("<a href=\"{0}/{1}/{2}\"><i class=\"{4}\"></i>{3}</a>", basePath, controller, action, text, iconClass)).ToString();

        return MvcHtmlString.Create(li.ToString());
    }

そして、次のように実装されています:

        <div id="sidebar">
            <ul>
                @Html.MenuItem("Dashboard", "Index", "Dashboard", "icon-home")
@*              <li class="active"><a href="dashboard.html"><i class="icon-home"></i> <span>Dashboard</span></a></li>*@
                <li class="submenu">
                    <a href="#"><i class="icon-beaker"></i> <span>UI Lab</span> <i class="arrow icon-chevron-right"></i></a>

                    <ul>
                        <li>@Html.MenuItem("Websites", "Index", "Websites", null)</li>
                        <li><a href="jquery-ui.html">jQuery UI</a></li>
                        <li><a href="buttons.html">Buttons &amp; icons</a></li>
                    </ul>
                </li>
                <li class="submenu">
                    <a href="#"><i class="icon-th-list"></i> <span>Form elements</span> <i class="arrow icon-chevron-right"></i></a>
                    <ul>
                        <li><a href="form-common.html">Common elements</a></li>
                        <li><a href="form-validation.html">Validation</a></li>
                        <li><a href="form-wizard.html">Wizard</a></li>
                    </ul>
                </li>

私が持っていないのは、サブメニュー項目のためのものです。

これを達成しようとするより簡単な方法はありますか?

- アップデート -

これを部分的なビューに入れるのが最善かもしれないと推測しています。現在のアイテムを「アクティブ」に設定するためにコントローラー/アクションが一致するかどうかを確認するのではなく、クリック時に選択したアイテムを保持してすべてのメニューアイテムで参照する方法を見つける必要があります。クリックでアクティブになるコントローラ メソッドは、現在選択されている項目が親か子かをチェックし、親が子と一致する場合は別の形式にしますか? もっと簡単な方法があるに違いないと確信しています。

4

2 に答える 2

5

さて、これが私が思いついた1つの解決策です。

要約すると、これは項目が選択されている場合に項目に「アクティブな」CSS クラスを追加するほど単純ではありません (デフォルトの Bootstrap MVC に従って)。このソリューションでは、親と子を識別し、両方を識別する必要があります。

ここに画像の説明を入力

デフォルトのページはダッシュボードです。次に、ユーザーは [構成] をクリックしてメニューを展開し、[Web サイト] リンクを選択してページを開きます。

解決策は次のとおりです。

モデル:

public class NavigationMenu
{
    public string Text { get; set; }
    public string Action { get; set; }
    public string Controller { get; set; }
    public string Icon { get; set; }
    public bool Selected { get; set; }

    public List<NavigationMenu> MenuChildren;
}

コントローラ:

public class NavigationController : Controller
{
    [ChildActionOnly]
    public ActionResult GenerateMenu()
    {
        List<NavigationMenu> menuItems = new List<NavigationMenu>();
        // build the menu
        menuItems.Add(new NavigationMenu
        {
            Text = "Dashboard",
            Action = "",
            Controller = "Dashboard",
            Icon = "icon-home",
            Selected = true,    // default selected menu item
            MenuChildren = null
        });
        menuItems.Add(new NavigationMenu
        {
            Text = "Configuration",
            Action = null,
            Controller = null,
            Icon = "icon-cog",
            MenuChildren = new List<NavigationMenu>{
                new NavigationMenu{
                    Text = "Websites",
                    Action = "",
                    Controller = "Websites",
                    Icon = null,
                    MenuChildren = null
                },
                new NavigationMenu{
                    Text = "Child 2",
                    Action = null,
                    Controller = null,
                    Icon = null,
                    MenuChildren = null
                }
            }
        });
        menuItems.Add(new NavigationMenu
        {
            Text = "Item 2",
            Action = "",
            Controller = "Item2",
            Icon = "icon-random",
            MenuChildren = null
        });
        menuItems.Add(new NavigationMenu
        {
            Text = "Item 3",
            Action = "",
            Controller = "Item3",
            Icon = "icon-certificate",
            MenuChildren = null
        });

        string action = ControllerContext.ParentActionViewContext.RouteData.Values["action"].ToString() == "Index" ? "" : ControllerContext.ParentActionViewContext.RouteData.Values["action"].ToString();
        string controller = ControllerContext.ParentActionViewContext.RouteData.Values["controller"].ToString();

        foreach (var item in menuItems)
        {
            if (item.MenuChildren != null)
            {
                foreach (var cItem in item.MenuChildren)
                {
                    if (cItem.Controller == controller && cItem.Action == action)
                    {
                        cItem.Selected = true;
                        break;
                    }
                    else
                    {
                        cItem.Selected = false;
                    }
                }
            }
            if (item.Controller == controller && item.Action == action)
            {
                item.Selected = true;
                break;
            }
            else
            {
                item.Selected = false;
            }
        }

        return PartialView("~/Views/Shared/_Navigation.cshtml", menuItems); 
    }

}

共有ビュー:

@model IEnumerable<AdminWebsite.Models.NavigationMenu>
@{
    var basePath = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);
}
<div id="sidebar">
    @Html.Raw("<ul>")
        @foreach (var item in Model)
        {
            // if the menu item does not have children then it should be clickable
            if (item.MenuChildren == null & item.Selected)
            {
                <li class="active"><a href="@String.Format("{0}/{1}/{2}", basePath, item.Controller, item.Action)"><i class="@item.Icon"></i> <span>@item.Text</span></a></li>
            }
            else if (item.MenuChildren == null & !item.Selected)
            {
                <li><a href="@String.Format("{0}/{1}/{2}", basePath, item.Controller, item.Action)"><i class="@item.Icon"></i> <span>@item.Text</span></a></li>
            }

            // has children and one of its children is selected
            if (item.MenuChildren != null)
            {
                if (item.MenuChildren.Any(c => c.Selected) == true)
                {                
                    <text><li class="submenu active open"></text>
                }
                else
                {
                    <text><li class="submenu"></text>
                }

                // sub-menu parent
                if (item.MenuChildren != null & item.Selected)
                {
                    <a href="@String.Format("{0}/{1}/{2}", basePath, item.Action, item.Controller)"><i class="@item.Icon"></i> <span>@item.Text</span></a>
                }
                else if (item.MenuChildren != null & !item.Selected)
                {
                    <a href="@String.Format("{0}/{1}/{2}", basePath, item.Action, item.Controller)"><i class="@item.Icon"></i> <span>@item.Text</span></a>
                }

                // children
                <text><ul></text>
                    // iterate through children
                    foreach(var cItem in item.MenuChildren)
                    {
                        if (cItem.MenuChildren == null & cItem.Selected)
                        {
                            <li class="active"><a href="@String.Format("{0}/{1}/{2}", basePath, cItem.Controller, cItem.Action)"><i class="@cItem.Icon"></i> <span>@cItem.Text</span></a></li>
                        }
                        else if (cItem.MenuChildren == null & !cItem.Selected)
                        {
                            <li><a href="@String.Format("{0}/{1}/{2}", basePath, cItem.Controller, cItem.Action)"><i class="@cItem.Icon"></i> <span>@cItem.Text</span></a></li>
                        }                    
                    }

                @Html.Raw("</ul>");


                @Html.Raw("</li>");
            }

        }
    @Html.Raw("</ul>")
</div>

ビューでの実装:

@{Html.RenderAction("GenerateMenu", "Navigation");}

コントローラーは、現在のアクション/コントローラー名がメニューの名前と一致するかどうかを確認し、一致する場合は を設定しselected = trueます。部分ビューでは、親子関係に基づいて表示構造を決定するロジックがあり、子が選択されている場合は親も選択されます。

要するに、それだけです。コメントやその他の例を聞きたいです。

于 2013-11-08T21:56:23.600 に答える
1

これは、受け入れられた回答のほとんどのコードを使用したソリューションであり、プロジェクトに合わせて名前を少し変更して、HtmlHelpers と TagBuilders を使用するようにリファクタリングされています。

モデル:

public class MenuViewModel
{
    public IList<MenuItemDto> MenuItems; 
}

public class MenuItemDto
{
    public string Text { get; set; }
    public string Action { get; set; }
    public string Controller { get; set; }
    public string IconCssClass { get; set; }
    public bool Active { get; set; }

    public List<MenuItemDto> MenuChildren;
}

コントローラ:

public ActionResult GenerateMenu()
{
    var viewModel = new MenuViewModel();
    viewModel.MenuItems = //code to build menu model like ElHaix provided in his Controller;

    return PartialView("~/Views/Shared/_Menu.cshtml", viewModel);
}

共有ビュー:

@using Extensions

<div id="sidebar">
    @Html.Raw("<ul>")

    @foreach (var item in Model.MenuItems)
    {
        // if the menu item does not have     children then it should be clickable
        if (item.MenuChildren == null)
        {
            @Html.LiForMenuItem(item)
        }

        // has children and one of its children     is selected
        if (item.MenuChildren != null)
        {
            if (item.MenuChildren.Any(c => c.    Active) == true)
            {
                <text><li class="submenu active     open">
                </text>
            }
            else
            {
                <text>
                <li class="submenu">
                </text>
            }

            // sub-menu parent
            if (item.MenuChildren != null)
            {
                @Html.HrefForSubMenuItemRoot(    item)
            }

            // children
            <text><ul>
            </text>
            // iterate through children
            foreach (var cItem in item.    MenuChildren)
            {
                if (cItem.MenuChildren == null)
                {
                    @Html.LiForMenuItem(cItem)
                }
            }
            @Html.Raw("</ul>");

        @Html.Raw("</li>");
        }

    }
    @Html.Raw("</ul>")
</div>

HTML ヘルパー:

namespace Extensions
{
    public static class MenuExtensions
    {
        public static MvcHtmlString LiForMenuItem(this HtmlHelper htmlHelper, MenuItemDto menuItem)
        {
            var li = new TagBuilder("li");
            AddActiveCssClassToTag(menuItem, li);
            var contentUrl = GenerateContentUrlFromHttpContext(htmlHelper);
            li.InnerHtml = GenerateLinkForMenuItem(menuItem, contentUrl);
            return MvcHtmlString.Create(li.ToString());
        }

        public static MvcHtmlString HrefForSubMenuItemRoot(this HtmlHelper htmlHelper, MenuItemDto menuItem)
        {
            var a = new TagBuilder("a");
            AddActiveCssClassToTag(menuItem, a);
            var contentUrl = GenerateContentUrlFromHttpContext(htmlHelper);
            a.Attributes.Add("href", GenerateUrlForMenuItem(menuItem, contentUrl));
            a.InnerHtml = GenerateInnerHtmlForMenuItem(menuItem);
            return MvcHtmlString.Create(a.ToString());
        }

        private static void AddActiveCssClassToTag(MenuItemDto menuItem, TagBuilder tag)
        {
            if (menuItem.Active)
            {
                tag.AddCssClass("active");
            }
        }

        private static string GenerateContentUrlFromHttpContext(HtmlHelper htmlHelper)
        {
            return UrlHelper.GenerateContentUrl("~/", htmlHelper.ViewContext.HttpContext);
        }

        private static string GenerateLinkForMenuItem(MenuItemDto menuItem, string contentUrl)
        {
            var a = new TagBuilder("a");
            a.Attributes.Add("href", GenerateUrlForMenuItem(menuItem, contentUrl));
            a.InnerHtml = GenerateInnerHtmlForMenuItem(menuItem);
            return a.ToString();
        }

        private static string GenerateInnerHtmlForMenuItem(MenuItemDto menuItem)
        {
            var html = string.Empty;

            //Add <i></i> if there is an IconCssClass present
            var i = new TagBuilder("i");
            if (!String.IsNullOrEmpty(menuItem.IconCssClass))
            {
                i.AddCssClass(menuItem.IconCssClass);
                html += i.ToString();
            }

            //add a span for the text of the menuItem
            var span = new TagBuilder("span");
            span.InnerHtml = menuItem.Text;

            html += span.ToString();

            return html;
        }

        private static string GenerateUrlForMenuItem(MenuItemDto menuItem, string contentUrl)
        {
            var url = contentUrl + menuItem.Controller;
            if (!String.IsNullOrEmpty(menuItem.Action)) url += "/" + menuItem.Action;
            return url;
        }
    }
}
于 2014-01-03T20:38:21.803 に答える