Tuesday, June 19, 2012

[MVC] MVC4的HtmlHelper Extension - 自製 Active Navigation Bar

asp-net-mvc

網站開發一定遇過網頁上有很多選項,這些選項又要用程式去生出來,還要去判斷選項是不是當前頁面來給予不同的CSS,原本的開發方式寫起來會很繁瑣又笨,但是在MVC上卻變得相當精美。

上述的問題以英文簡單來說就是Active Navigation Bar,所以我就用這個來當範例。


Active Navigation Bar

原本的prototype長的這個樣子。
MVC4-01

轉成MVC寫法會變成大概這個樣子。
<ul>
 <li>@Html.ActionLink("Home", "Index", "Home")</li>
 <li>@Html.ActionLink("FAQ", "FAQ", "Home")</li>
 <li>@Html.ActionLink("Contact Us", "Contact", "Home")</li>
</ul>

東西看起來是好了,但是還要去另外判斷目前的頁面來改CSS實在是很麻煩的一件事,這時候就可以用HtmlHelper Extension來精美的處理掉這件事。


HtmlHelper Extension

我是另外寫了一個叫做ActiveNavigationBar的功能去專門處理Navigation Bar這件事,用TagBuilderActionLink組出我要的東西,然後借用demo小鋪ASP.NET MVC 如何判斷現在是哪一頁這個功能去判斷使否在那頁,再去增加<li>的class,所以語法如下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace TestMVC.Common
{
    public static class Helpers 
    {
        public static MvcHtmlString ActiveNavigationBar(this HtmlHelper helper, string linkText, string actionName, string controllerName)
        {
            if (IsCurrentAction(helper, actionName, controllerName))
                {
                    return ListLink(helper, linkText, actionName, controllerName, true);
                }
            return ListLink(helper, linkText, actionName, controllerName);
        }

        private static MvcHtmlString ListLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, bool active)
        {
            var builder = new TagBuilder("li");
            if(active) builder.AddCssClass("active");
            builder.InnerHtml = helper.ActionLink(linkText, actionName, controllerName).ToHtmlString();
            return new MvcHtmlString(builder.ToString());
        }

        private static MvcHtmlString ListLink(this HtmlHelper helper, string linkText, string actionName, string controllerName)
        {
            return ListLink(helper, linkText, actionName, controllerName, false);
        }

        //from domo
        public static bool IsCurrentAction(this HtmlHelper helper, string actionName, string controllerName)
        {
            string currentControllerName = (string)helper.ViewContext.RouteData.Values["controller"];
            string currentActionName = (string)helper.ViewContext.RouteData.Values["action"];

            if (currentControllerName.Equals(controllerName, StringComparison.CurrentCultureIgnoreCase) &&
                currentActionName.Equals(actionName, StringComparison.CurrentCultureIgnoreCase))
                return true;

            return false;
        }
    }
}
有點長,我懶得排版了,反正他就會自動判斷要不要加css上去,如果有特例的地方也可以自行加上,我貼上的是沒有特例的版本。

另外我想應該是MVC4的安全性考量(not sure),現在的版本用string輸出HtmlHelper到頁面上,會變成HtmlEncode過的格式,一個解法是在頁面上多做一次處理,另外一個就是改後端輸出了,所以我是寫成輸出為MvcHtmlString,而不是一般大部分人在HtmlHelper Extension寫的輸出為String。


Front-end

於是在頁面上引用這個Extension之後
@using TestMVC.Common;
就可以很精美的處理掉繁雜的Active Navigation Bar問題了。

MVC4-02

收工!!

No comments:

Post a Comment