5.3 Razor語法基礎

      以往開發ASP.NET Web Form時,在ASPX頁面上都會出現許多夾雜C#/VB.NET與HTML的狀況,而先前使用<%...%>這種傳統圓角括號的表示法會讓HTML標籤與ASP.NET代碼區塊混雜一塊兒,當頁面變得複雜後,這類混合的代碼也開始變得難以閱讀,相信你們都有相同的感覺。html

      從ASP.NET MVC3開始引入了全新的Razor語法,用@符號來表明代碼段,試圖提供一個容易學習又精簡的語法。Razor語法推出以後,廣受ASP.NET MVC開發人員的喜好,搭配Visual Studio開發工具的語法高亮顯示下,Razor語法也讓整份View頁面內的HTML標籤與服務器代碼結合得很是漂亮,再也不有吃意大利麪的感受了。web

      咱們先來回顧以往ASP.NET Web Form在ASPX頁面上輸出當前時間的表示法:瀏覽器

<%: DateTime.Now %>

      若使用Razor語法,將會變成如下撰寫風格安全

@DateTime.Now

      Razor並非一個代碼語言,它只是一種用在View頁面的代碼區塊撰寫風格罷了,所寫的代碼同樣是C#或VB.NET,所以開人員並不用額外學習過多的語言就能快速上手。
      若要使用C#語言來編寫Razor頁面,View頁面的擴展名必須使用cshtml才行。同理VB.NET語言,要用vbhtml。服務器

1.Razor基本語法架構

      在頁面中輸出單一變量時,只要在C#語句以前加上@符號便可。mvc

<p>
    如今時刻:@DateTime.Now
</p>

      請注意,上述範例中雖然使用C#語言編寫代碼,但輸出單一變量時不須要加上分號結尾。在頁面中輸出一段含有表達式的結果時,必須在先後加上一個小括號。app

<p>
    會員名稱:@(User.Identity.Name+Model.MemberLevel)
    啓用狀態:@(ViewBag.IsEnabled?"啓用":"停用")
</p>

      在頁面中執行多行C#代碼時,必須在先後加上個大括號。框架

@{
    var name="Will";
    var message="你好,我是 "+name;
}

      請注意,上述範例中因爲@{到}之間屬於一個C#代碼區段,在撰寫代碼時必須符合C#語言規範,也就是每句話都要有分號結尾。
      若是要在多行C#代碼的Razor語法中插入HTML或其餘文字內容,必須在每一行最前面加上一個「@:」符號,並且加上「@:」符號的這行代碼裏,也能夠再加上其餘Razor變量。asp.net

@{
    var name="Will";
    @:你好,我是@name
}

      若是要在Razor視圖頁面中標識服務器端註釋,可使用「@*」與「*@」來當註解的頭尾。

@*<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
    <h2>@ViewBag.Message</h2>
</hgroup>*@

      若是要在Razor視圖頁面中輸出"@"符號。

@@Will_Huang

      上述Razor語法最後會輸出「@Will_Huang」。

2.Razor與HTML混合輸出

      在View視圖裏混合使用HTML標籤與Razor語法,在許多狀況下能夠用得很是順利,但若是不瞭解Razor的判斷邏輯,也可能會讓你在開發的過程當中不斷受挫,如今就來介紹幾個經常使用的混合編寫風格。

      在頁面中編寫if判斷句,其範例以下:

@if (ViewBag.IsEnabled){
    @:啓用
} else {
    @:停用
}

      若是要在代碼區塊中輸出大量文字,只要在代碼區塊裏的先後加上一組HTML標籤便可,Razor會只能地判斷出這不是一段C#語法,而是一段HTML標籤文字,如此一來,就不用在每一行前面加上「@:」符號了,以下所示。

@if (ViewBag.IsEnabled)
{
    <span>啓用</span>
} else {
    <span>停用</span>
}

      VS2012提供Razor語法的高亮顯示,只要是Razor可被識別的C#代碼,都會在背景加上一個淡淡的藍色,若是是白底色的話,那就表明是Razor之外的純文字。

      若是咱們在這個區段中徹底不想輸出任何先後的標籤該怎麼辦呢?在Razor頁面裏,可使用特殊的<text>標籤來代替這個HTML標籤,最後輸出到瀏覽器時不會輸出<text>這個標籤,以下所示。

複製代碼
@if (ViewBag.IsEnabled)
{
    <text>
        顯示啓用的HTML段落:
       <p>
           @ViewBag.EnabledMessage
       </p>
    </text>
} else {
    <text>
        顯示停用的HTML段落:
       <p>
           @ViewBag.DisabledMessage
       </p>
    </text>
}
複製代碼

3.Razor與HTML混合輸出陷阱與技巧

(1)屬性名稱誤判

      有時候咱們必須讓HTML內容與Razor語句牢牢黏在一塊兒。顯示效果爲,「您好,Will先生」,其中Will爲一個變量ViewBag.Name。若是輸入如下Razor語法:

您好,@ViewBag.Name先生

      這句話中,Razor會把「@ViewBag.Name先生」當成一個C#語法,修改以下:

您好,@(ViewBag.Name)先生

      另外一種解決方法就是多用一個HTML標籤包起來,以下:

您好,<span>@ViewBag.Name</span>先生

      或修改以下:

您好,@ViewBag.Name<span>先生</span>

(2)未預期的額外屬性

      要輸出以下。

類別是System.Web.Mvc.Controller

      若是按如下輸出,會出錯。

@{
    ViewBag.MvcNamespace="System.Web.Mvc";
}

類別是@ViewBag.MvcNamespace.Controller

      如何修改?

類別是@(ViewBag.MvcNamespace).Controller

(3)輸出Email地址與@轉義符

      若是咱們要在Razor頁面中輸出Email超連接,輸出的結果多是這樣:

<a href="mailto:teacher@example.com">teacher@example.com</a>

      這裏並不須要改爲@@,由於Razor會自動判斷先後文,只要"@"的前面與後面都有文字的狀況下,@就會停用Razor語法解析,因此在Razor裏輸入Email是徹底不用編寫「@」轉義字符。
      若是要輸出的HTML格式以下:

<a id="LinkBlog01" href="http://blog.miniasp.com">The will will web</a>

       要將Blog01替換成Razor變量,那又應該如何輸入呢?

@{
    ViewBag.BlogID="Blog01";
}

<a id="Link@View.BlogID" href="http://blog.miniasp.com">The will will web</a>

       以上代碼將不會被正常解析。解決方法能夠加上小括號。

<a id="Link@(View.BlogID)" href="http://blog.miniasp.com">The will will web</a>

(4)輸出未經HtmlEncode的字符串

      預設使用Razor語法輸出變量,全部內容預設都會被HTML編碼(HtmlEncode),這是爲了保護網頁不致遭受跨網站腳本攻擊(Cross-Site Scripting, XSS),有了這個預設值,能保證新手開發人員不寫出不安全的代碼。

@{
    ViewBag.Description="<span style='font-weight:bold;'>描述文字</span>";
}

@ViewBag.Description

     最後輸出的結果會是HtmlEncode過的版本以下:

&lt;span style=&#39;font-weight:bold;&#39;&gt;這是描述文字&lt;/span&gt;

   若是咱們要強迫字符串原封不動地輸出,能夠利用@Html.Raw輔助方法幫助咱們輸出內容,咱們能夠修改上述Razor代碼,代碼以下:

@{
    ViewBag.Description="<span style='font-weight:bold;'>這是描述文字</span>";
}

@Html.Raw(ViewBag.Description)

   最後的輸出以下:

這是描述文字

4.Razor的母版頁面框架

     傳統的ASP.NET從2.0版開始推出了MasterPage母版頁面框架,讓你在ASP.NET Web Form頁面能夠經過MasterPage組織出全站一致的外觀與界面。而ASP.NET MVC 1.0/2.0也沿用MasterPage架構組織View頁面的HTML版面架構,不過,ASP.NET MVC 3.0推出的RazorView內建的母版頁面語法與本來的WebFormView的MasterPage相差甚遠,所以,你能夠把Razor母版頁面當成是一個全新的架構來學習,只是母版頁面子觀念上是差很少的。

(1)Razor頁面執行順序

      當Controller回傳ViewResult給MvcHandler以後,MvcHandler會先設法找出對應的視圖頁面,當找到適當的Razor頁面後,就會進入Razor頁面執行生命週期,在Razor頁面的執行過程當中有個固定的執行順序。

      被MvcHandler找到的Razor頁面會優先執行,執行完畢後,會檢查這個View頁面是否含有母版頁面所需的Layout屬性,若是有的話便試圖載入Layout屬性指定的Razor母版頁面,找到母版頁面以後會開始將內容響應給用戶端。

      咱們先以傳統ASP.NET Web Form的MasterPage做爲例子,當MasterPage執行的時候,會先找出ContentPlaceHolder控制項,並將以前母版頁面的執行結果填入後輸出到用戶端。以下所示:

<asp:ContentPlaceHoder ID="MainContent" runat="server" />

      實際上在溝通的時候,會把這種在MasterPage定義一個區塊的動做戲稱爲「挖洞」,也就是在MasterPage裏挖了一個洞,而後由主要頁面的內容填入。
      在Razor裏,當母版頁面被載入後,執行的過程也同樣,在Razor母版頁面裏也會定義出一些須要被填入的內容(挖洞),而後讓主要頁面的內容填入。

(2)關於_ViewStart文件

       /Views/_ViewStart.cshtml文件會在/Views/目錄下任何View被載入前就先被載入,也就是View視圖頁面在執行以前,必定會先來這裏尋找有沒有/Views/_ViewStart.cshtml這個文件,只要有這個文件就會先載入執行。

      接着再來看看這個預設文件的內容,此文件只包含了一行指定Layout屬性的代碼,所表明的的意義是:全部/Views/目錄下的View預設都要以~/Views/Shared/_Layout.cshtml爲母版頁面。

      這個_ViewStart.cshtml文件不只能出如今/Views/目錄下,任何與Controller同名的Views子目錄下也都能出現相同的_ViewStart.cshtml文件,如此一來,就可讓不一樣的Controller預設載入不一樣的母版頁面。

(3)關於_Layout母版頁面 

      /Views/Shared/_Layout.cshtml文件,有兩個Razor語法,分別是@RenderBody與@RenderSection這兩段聲明,而這就是所謂的「挖洞宣言」,以下所示。

複製代碼
        </header>
        <div id="body">
            @RenderSection("featured", required: false)
            <section class="content-wrapper main-content clear-fix">
                @RenderBody()
            </section>
        </div>
複製代碼

      @RenderBody()在Razor母版頁面中能夠視爲「預設坑洞」,也就是主要的View頁面在沒有特別聲明的狀況下,全部內容都會被填入到@RenderBody()這個位置。
      @RenderSection在Razor母版頁面中能夠被視爲「具名坑洞」,如下語法爲例,咱們在母版頁面中定義了一個名爲featured的坑洞,第二個required具名參數則是聲明這個坑洞是否必須被填滿,若是你在母版頁面設定的「具名坑洞」把required參數指定爲true的話,那麼全部載入這個母版頁面的View頁面都必須輸出相對應的內容,不然就會發生異常情況。

@RenderSection("featured", required:false)

      在Index.cshtml頁面,可使用一個特殊的Razor語法,名爲@section,且在後面必須接上一個「坑洞名稱」,好比featured,而在這個@section featured聲明裏,對Razor來講這就是一個代碼區塊,所套用的Razor規則也都同樣。

複製代碼
@{
    ViewBag.Title = "Home Page";
}
@section featured {
    <section class="featured">
        <div class="content-wrapper">
            <hgroup class="title">
                <h1>@ViewBag.Title.</h1>
                <h2>@ViewBag.Message</h2>
            </hgroup>
            <p>
                To learn more about ASP.NET MVC visit
                <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
                The page features <mark>videos, tutorials, and samples</mark> to help you get the most from ASP.NET MVC.
                If you have any questions about ASP.NET MVC visit
                <a href="http://forums.asp.net/1146.aspx/1?MVC" title="ASP.NET MVC Forum">our forums</a>.
            </p>
        </div>
    </section>
}
複製代碼

5.@helper輔助方法

      Razor提供了一種很方便的語法,讓你能夠將View頁面中部份內容或部分代碼抽取出來,變成一個獨立的輔助方法。

複製代碼
@helper ShowUnitPrice(int price)
{
    if(price==0)
    {
        @:免費
    }else{
        @price
    }
}
複製代碼
複製代碼
@foreach(var item in Model)
{
    <tr>
        <td>
            @item.Name
        </td>
        <td>
            @item.Description
        </td>
        <td>
            @ShowUnitPrice(item.UnitPrice)
        </td>
    </tr>
}
複製代碼

      其實聲明@helper輔助方法的語法與在C#中聲明方法的方式很是像,惟一的差異就在於不用回傳任何類型,預設就是網頁輸出,十分方便。你能夠把這種編寫風格當成是Razor版的代碼片斷。
      若是要將這個@heper輔助方法用在多個不一樣的View頁面裏,你能夠考慮將@helper輔助方法獨立出來,放置在項目根目錄App_Code下,放置在新建的MVC4佈局頁(Razor)UIHelper.cshtml中。以下所示。

      最後再改寫本來循環內的@ShowUnitPrice方法,代碼以下:

6.@functions自定義函數

     @helper輔助方法的確能夠很方便地完成輔助方法開發,不過卻失去了一些彈性,例如,沒法在@helper輔助方法中自定義屬性(Property),只能單純地傳入參數,而後格式化成你想要呈現的樣子後直接輸出。所以,Razor還提供了@functions自定義函數功能,可以讓你用接近C#類的方式進一步定義更復雜的輔助方法。

複製代碼
@functions{
    public IHtmlString GetYesterday()
    {
        var theDay = DateTime.Now.AddDays(-1);
        return new HtmlString(theDay.ToShortDateString());
    }
}
複製代碼

      在與@functions同一頁裏,就能使用上述定義的@GetYesterday()方法來執行。與@helper輔助方法相同,若是但願在多個不一樣的View頁面裏都能使用這個由@functions定義的方法,你也能夠將這段@functions聲明移到項目根目錄的App_Code目錄下的其中一個cshtml文件裏。不過,在搬移@functions代碼聲明時有一個小地方須要注意,就是必需要聲明方法爲靜態(static)才能讓各頁面取用,以下。

複製代碼
@functions{
    public static IHtmlString GetYesterday()
    {
        var theDay = DateTime.Now.AddDays(-1);
        return new HtmlString(theDay.ToShortDateString());
    }
}
複製代碼

7.@model引用模型類型

      在Razor頁面裏能夠在頁面最上方經過@model語法設定一組View頁面的強類型數據模型參考,套用了數據模型後,在這個View頁面裏就能夠用具備類型的方式取用Model。

@model IEnumberable<MvcApplication6.Models.Product>

      請注意@model語法的第一個字母是小寫m,千萬不要和Model搞混了。

8.@using引用命名空間

      在Razor頁面裏能夠在頁面最上方經過@using引用這一個View頁面裏會用到的命名空間,以簡化程序的長度。

@using MvcApplication6.Models
@model IEnumberable<Product>

     在ASP.NET MVC項目的Views\web.config配置文件中,有個<system.web.webPages.razor>區段設定,底下有個<namespace>區段設定了全部View頁面都會引入的命名空間,若是大部分視圖頁面都要引用相同命名空間的話,能夠在這裏設定載入,如此一來,就不用在每頁最上方加上@using語法了,以下所示。

複製代碼
   <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization"/>
        <add namespace="System.Web.Routing" />
        <add namespace="MvcApplication6.Models"/>
      </namespaces>
    </pages>
複製代碼
相關文章
相關標籤/搜索