ASP.NET MVC 5 Web編程4 -- Razor視圖引擎


Razor簡介

Razor是ASP.NET新增的一個視圖引擎,由微軟全球最年輕的副總裁,有着"ASP.NET之父"稱呼的Scott Guthrie主導的團隊開發。

主導Razor開發的Scott Guthrie,畢業於美國杜克大學。現任微軟雲計算與企業級產品工程部執行副總裁。

Razor對傳統aspx頁面的寫法和頁面渲染能力提出了反思,所以它在代碼書寫和HTML生成方面都進行了優化。Rzaor的設計目標遵循以下幾點:

a). 盡量減少代碼

b). 上手快,只需要現有的編程語言和基本的HTML知識

c). 可以使用記事本編寫

d). 便於單元測試

Rzaor視圖引擎頁面以.cshtml(或.vbhtml)文件后綴結尾,是ASP.NET MVC 5默認使用的頁面展現形式。

Razor與.aspx視圖引擎對比

為了有一個直觀的認識,我們先來看一個簡單的用戶管理頁面的實現:

假定上圖的頁面呈現效果就是我們的最終目標。先來看Razor實現的頁面:

@{
    Layout = null;
}

@model IEnumerable<MVC5Demo.Models.UserInfoViewModel>

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
    <title></title>
</head>
<body>
    <div>
        @Html.ActionLink("新增", "Add", "UserInfo")
        <hr />
        <h3>用戶信息列表</h3>
        <div class="table-responsive">
            <table class="table table-striped table-bordered">
                <thead>
                    <tr>
                        <th>姓名</th>
                        <th>性別</th>
                        <th>年齡</th>
                        <th>部門</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var item in Model) { 
                    <tr>
                        <td>@Html.DisplayFor(p => item.UserName)</td>
                        <td>@(item.Sex == 0 ? "" : "")</td>
                        <td>@Html.DisplayFor(p => item.Age)</td>
                        <td>@Html.DisplayFor(p => item.Dept)</td>
                        <td>@Html.ActionLink("編輯", "Edit", "UserInfo", new { id=item.UserID.ToString() },null) @Html.ActionLink("刪除", "Delete", "UserInfo", new { id = item.UserID.ToString() }, new { onclick="return confirm('確認刪除"+item.UserName+"的記錄?');" })</td>
                    </tr>
                    }
                </tbody>
            </table>
        </div>

    </div>
</body>
</html>
View Code

同時貼出傳統aspx頁面的代碼(注:樣式代碼部分省略):

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="MVC5Demo.WebForms.UserInfo.WebForm1" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:LinkButton runat="server" Text="新增" PostBackUrl="~/add.aspx" />
    <div style="height: 267px">
        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" >
            <Columns>
                <asp:BoundField DataField="UserName" HeaderText="姓名" />
                <asp:BoundField DataField="Sex" HeaderText="性別" />
                <asp:BoundField DataField="Age" HeaderText="年齡" />
                <asp:BoundField DataField="Dept" HeaderText="部門" />
                <asp:CommandField HeaderText="編輯" ShowEditButton="true" />
                <asp:CommandField HeaderText="刪除" ShowDeleteButton="true" />
            </Columns>
        </asp:GridView>
    </div>
    </form>
</body>
</html>
View Code

站在Razor的角度,

與傳統aspx頁面實現的代碼不同,主要是以下幾點:

1. 沒有使用"GridView" 服務器控件(或者說沒有這樣的控件可以使用);

2. 使用@符號代替<%= %>來訪問服務器代碼;

3. 使用MVC提供的HTML輔助函數來渲染頁面(代替服務器控件形式);

4. 其他不同點(如頁頭)。

可以看到,Razor的頁面處理更"精細",在頁面展示上有點類似jsp(或者說回到了asp?),你需要具備基本的HTML知識(如畫Table),因為"視圖設計器","服務器控件"這些你曾經熟悉的東西,"不存在"了。

我們再來看看兩種視圖引擎生成的HTML源代碼的差異。先來看Razor頁面生成的HTML:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <link href="/Content/bootstrap.min.css" rel="stylesheet" />
    <title></title>
</head>
<body>
    <div>
        <a href="/UserInfo/Add">新增</a>
        <hr />
        <h3>用戶信息列表</h3>
        <div class="table-responsive">
            <table class="table table-striped table-bordered">
                <thead>
                    <tr>
                        <th>姓名</th>
                        <th>性別</th>
                        <th>年齡</th>
                        <th>部門</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>lili</td>
                        <td></td>
                        <td>22</td>
                        <td>Human Resource</td>
                        <td><a href="/UserInfo/Edit/e92cfb5c-e81a-4cfc-9d85-1bc77f9fab75">編輯</a> <a href="/UserInfo/Delete/e92cfb5c-e81a-4cfc-9d85-1bc77f9fab75" onclick="return confirm(&#39;確認刪除lili的記錄?&#39;);">刪除</a></td>
                    </tr>
                    <tr>
                        <td>zhangsan</td>
                        <td></td>
                        <td>0</td>
                        <td>Resource</td>
                        <td><a href="/UserInfo/Edit/e4b9c9f2-afd4-45f4-bb3d-1ca2c91642b3">編輯</a> <a href="/UserInfo/Delete/e4b9c9f2-afd4-45f4-bb3d-1ca2c91642b3" onclick="return confirm(&#39;確認刪除zhangsan的記錄?&#39;);">刪除</a></td>
                    </tr>
                    <tr>
                        <td>hangwei</td>
                        <td></td>
                        <td>26</td>
                        <td>Technology</td>
                        <td><a href="/UserInfo/Edit/3fdc971a-20c0-4016-b09b-703db265e972">編輯</a> <a href="/UserInfo/Delete/3fdc971a-20c0-4016-b09b-703db265e972" onclick="return confirm(&#39;確認刪除hangwei的記錄?&#39;);">刪除</a></td>
                    </tr>
                    <tr>
                        <td>xiaoya</td>
                        <td></td>
                        <td>20</td>
                        <td>Human Resource</td>
                        <td><a href="/UserInfo/Edit/64bb557a-0eae-4554-8258-99412f4a0c78">編輯</a> <a href="/UserInfo/Delete/64bb557a-0eae-4554-8258-99412f4a0c78" onclick="return confirm(&#39;確認刪除xiaoya的記錄?&#39;);">刪除</a></td>
                    </tr>
                    <tr>
                        <td>lulu</td>
                        <td></td>
                        <td>19</td>
                        <td>public relation</td>
                        <td><a href="/UserInfo/Edit/d2da9745-8423-468d-b16c-a5f1e220228b">編輯</a> <a href="/UserInfo/Delete/d2da9745-8423-468d-b16c-a5f1e220228b" onclick="return confirm(&#39;確認刪除lulu的記錄?&#39;);">刪除</a></td>
                    </tr>
                </tbody>
            </table>
        </div>

    </div>

<!-- Visual Studio Browser Link -->
<script type="application/json" id="__browserLink_initializationData">
    {"appName":"InternetExplorer","requestId":"e66859a98d6d44589621dafbc30ed07b"}
</script>
<script type="text/javascript" src="http://localhost:38131/ed029686c8c448a4ad16768559cf6138/browserLink" async="async"></script>
<!-- End Browser Link -->

</body>
</html>
View Code

總的來說,非常"干凈"。跟Razor書寫的代碼幾乎一樣。再來看aspx頁面生成的HTML:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>

</title></head>
<body>
    <form method="post" action="WebForm1.aspx" id="form1">
<div class="aspNetHidden">
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="dGzszrXmAWyS03LAAgn9Mu1+oe52zJZWXOwK8eBrCoGaaS/NrVfZYEyrJvwBzrLQUvloUdjMnLIMY6ou+eUPBQzAbrXsu1pxuWUlqErhvIGpI/ZFKrtfWqhpA1Eh5Dwn8ITIgsK9q4FP+qZ7dHk7EdtIwrvR4JHcwaBwS1jc17WIRdeeMDIfC3/Bo4fED1739IKFjjnc6Wo+8LjZ/gvo/NY3Z6aKjdPrOd7Kaiali/xL8TvA6q51KDyb0xn+FIOs4gKtotrzhfrB6mjRlgSU9VRv/V8vghdES0qtH7zRBNgUK+APeUNrdWvbS/bdNbtOqmmyAAUhj+UxB98lP1Uq2/6GwNKdUhcqfPyB1tFVGKtASLQnSRyvhMHReAn6SlMFGbr/Iks8DG2ZGHpe9+9walyoEwkYSO3HwbJx8ZwYilUuAPnaXm9PhtrBmfKS+JWln9qPTz5Ene1+cfRMo/JrOv9PHE7geq5apg5XbqEONnHMRp5gf6foGSUozbmkjEPrqtVal8cmVMyLYFXmegRS0QNhyUxf9MW4O392d0FnpCqWomY6iX7f1Zufd8rfAA6/shzOd4tKmHr+aDnXjeEjVuPn4MAQj7F2SAKonTwn7MbHpStwqggpax6ouj9Rv1F2Apew7oe6RTcf4jD1PGneseg32CVZlgtDO/jU38wW8Ot56dqayPEq6WNXUPbyJ/jUbT4bKWcN7TllXjdBfIiqo5puP4ZFkK1Jeeeah7oScwU=" />
</div>

<script type="text/javascript">
//<![CDATA[
var theForm = document.forms['form1'];
if (!theForm) {
    theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
//]]>
</script>


<script src="/WebResource.axd?d=pynGkmcFUV13He1Qd6_TZPjjg_3PjzXOZ2RR84591qrPEBSFqiIUM7TmWtTTY9Q7RVnJXgsOCIupr1tET1vQvA2&amp;t=635586541120000000" type="text/javascript"></script>

        <a href="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(&quot;ctl03&quot;, &quot;&quot;, false, &quot;&quot;, &quot;../add.aspx&quot;, false, true))">新增</a>
    <div style="height: 267px">
        <div>
    <table cellspacing="0" rules="all" border="1" id="GridView1" style="border-collapse:collapse;">
        <tr>
            <th scope="col">姓名</th><th scope="col">性別</th><th scope="col">年齡</th><th scope="col">部門</th><th scope="col">編輯</th><th scope="col">刪除</th>
        </tr><tr>
            <td>lili</td><td>0</td><td>22</td><td>Human Resource</td><td><a href="javascript:__doPostBack(&#39;GridView1&#39;,&#39;Edit$0&#39;)">編輯</a></td><td><a href="javascript:__doPostBack(&#39;GridView1&#39;,&#39;Delete$0&#39;)">刪除</a></td>
        </tr><tr>
            <td>zhangsan</td><td>0</td><td>0</td><td>Resource</td><td><a href="javascript:__doPostBack(&#39;GridView1&#39;,&#39;Edit$1&#39;)">編輯</a></td><td><a href="javascript:__doPostBack(&#39;GridView1&#39;,&#39;Delete$1&#39;)">刪除</a></td>
        </tr><tr>
            <td>hangwei</td><td>1</td><td>26</td><td>Technology</td><td><a href="javascript:__doPostBack(&#39;GridView1&#39;,&#39;Edit$2&#39;)">編輯</a></td><td><a href="javascript:__doPostBack(&#39;GridView1&#39;,&#39;Delete$2&#39;)">刪除</a></td>
        </tr><tr>
            <td>xiaoya</td><td>0</td><td>20</td><td>Human Resource</td><td><a href="javascript:__doPostBack(&#39;GridView1&#39;,&#39;Edit$3&#39;)">編輯</a></td><td><a href="javascript:__doPostBack(&#39;GridView1&#39;,&#39;Delete$3&#39;)">刪除</a></td>
        </tr><tr>
            <td>lulu</td><td>0</td><td>19</td><td>public relation</td><td><a href="javascript:__doPostBack(&#39;GridView1&#39;,&#39;Edit$4&#39;)">編輯</a></td><td><a href="javascript:__doPostBack(&#39;GridView1&#39;,&#39;Delete$4&#39;)">刪除</a></td>
        </tr>
    </table>
</div>
    </div>
    
<div class="aspNetHidden">

    <input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="B24E7CB3" />
    <input type="hidden" name="__PREVIOUSPAGE" id="__PREVIOUSPAGE" value="cLskMNrn93I_KrBWtzNjrdnU4nEVf6xwwXS72kJcSzZSQTv9se1ft7fisMnkWVQ7Z1_Y9_pWYR72hqYsEfzaCrwR6i_KuWzhFn_wlzM3p741" />
    <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="9sDy55QrEe0ZfiQhGKNvPEncESgVyis86+m/35or5jtV71SyrczxxZtNqnclLUIYCY9SxVMVhFTtH6/dC1a0JcJVCXr3M2w7+s4NlG+yZzYeecp4VCuGddyDMFStphryD6ncUMbxyJg5pLmFN56lo48qLRH9fBpud2tV4CyA4R1XsSIq6tmqduRgR43l/GP82S6BAn8w8pjMhqiw93soSt1S0Rt+QbNzDL/3mcJBpwn+yFK5gF0DuOly6Bb3OAv5HFp90N/rFDjogMMY+eHhOx97R/7BKXyqfyhKG3wg0H2ek4zQlKVhzC7KwX56hq1rD5SrQpg+u0qTdaxkZsOKuw==" />
</div></form>

<!-- Visual Studio Browser Link -->
<script type="application/json" id="__browserLink_initializationData">
    {"appName":"InternetExplorer","requestId":"20a0a7414285497caad40f738f0947ce"}
</script>
<script type="text/javascript" src="http://localhost:38131/ed029686c8c448a4ad16768559cf6138/browserLink" async="async"></script>
<!-- End Browser Link -->

</body>
</html>
View Code

直觀的,多了些"ViewState"。以上對比是不是就能說明MVC從性能和書寫方面比WebForms好呢?

關於這點,首先注意Razor介紹里,Razor是一個獨立的渲染引擎。至今為止沒有專業的團隊從性能的角度去測試它和WebForms的區別並給出實際結果的(估計結果相差不大)。其次,我個人比較贊同老趙的觀點(為WebForms說幾句話),高性能Web應用程序大多與具體所用的實現技術無關。MVC和WebForms各有各的好處和適合的應用場景,一味的壓低WebForms抬高MVC,有種跟風和牆頭草嫌疑。

Razor語法

1). @標示符

     @符號表示Razor代碼塊的開始,無需像WebForms那樣,加'%>'表示結束。Razor會自動從@符號的右邊開始,判斷哪些是后台代碼,哪些是前台HTML。

     

 

2). 普通輸出

     如在.cshtml文件中,輸入下面的代碼:

@DateTime.Now;

     前台會顯示什么呢?如下圖:

     

     前台顯示 時間+";"(注意這個分號),在單語句@符號后,進行代碼書寫,是不需要加分號的,加分號會被當做HTML文本來輸出到前台。

     如果進行代碼和文本混合編寫,可以這樣:

時間 @DateTime.Now 星期: @DateTime.Now.DayOfWeek

     文本和Razor代碼,中間加空格,這樣視圖引擎就可以判定@后是代碼部分。

     關於文本和代碼混合,還有一種簡單的方式:

@("today is :" + DateTime.Now.Year + "year.")

     使用@(),來進行多符號語句輸出。

 

3). 在語句塊中輸出

     語句塊,使用@{}來表示一段代碼。

        @{
            @DateTime.Now.Month;
            <br />
            <label>塊中變量輸出:</label>
            int x = 8;
            @x;
        }

      在語句塊中,需要注意的是:

      a. 使用@符號進行輸出,並且由於塊中遵循C#代碼機制,建議加分號(';'),這個分號不會輸出到前台頁面;

      b. 直接使用HTML標簽,會自動被識別為前台代碼。這點真的很方便,想想在一個C#代碼的編譯環境,直接寫HTML標簽輸出...;

      c. 不能直接輸出字符,如直接在代碼塊中書寫"Test" ,Test 等,都是不被允許的,請謹記代碼塊中遵循的是C#(或VB)環境;

      d. 其它書寫方式同后台代碼。

 

4). HTML輔助函數 

     以往的方式,我們是在代碼中向前台輸出HTML文本,這可以實現,但,不是很理想。像我本人,以前還使用了像jsrender這樣的頁面渲染方式。現在,借助於Razor的HTML輔助函數,可以輕松實現代碼輸出HTML。

     使用@helper 語法,自定義輔助函數(代碼片段可以放在任意位置)。

    @helper pList(List<string> lst)
    {//HTML輔助函數
        <ul>
            @foreach (string p in lst)
            {
                <li>@p</li>
            }
        </ul>
    }

      然后使用

        HTML輔助函數:
        @{
            List<string> lsts = new List<string> { "a", "b", "c", "d", "e" };
            @pList(lsts);
        }

      由於定義了名為pList的函數,使用時直接調用即可。

 

5). 其它

      a)一些書寫習慣,作用上是等價的,如條件判斷、循環分支:

        @if (1 == 1) { 
        }
        @foreach (string p in lsts){
        }
        @{
            if (1 == 1) { }
            foreach (string p in lsts) { }
        }

       b)代碼注釋,使用@*  ...  *@

        @*
            代碼注釋符:
            http://www.cnblogs.com/hangwei
        *@

       c)輸出@符號,使用 @@

       d)字符串轉換

       字符串轉換:
        @{
            string str = "10000";
            @str.AsInt();//在塊中遵循后台代碼形式
        }

 

6). 布局(模板)的使用

     a)layout布局頁的使用

     首先你需要在MVC工程下的Views/Shared目錄下,新建一個視圖文件(此目錄默認用來存放layout(模板)文件)。這里我們新建一個TestLayout.cshtml,代碼如下:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
</head>
<body>
    <div>
    1.TestLayout是模板頁 @DateTime.Now.ToString("HH:mm:ss.fff")
    </div>
    <div id="content"><!--內容頁的內容會出現在此div中-->
        @RenderBody()
    </div>
</body>
</html>

定義好布局頁的內容 ,子頁的部分,用@RenderBody()表示。再新建一個子頁套用此布局頁,代碼如下:

@{
    Layout = "~/Views/Shared/TestLayout.cshtml";
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
</head>
<body>
    <div>
    2.Index頁面 @DateTime.Now.ToString("HH:mm:ss.fff")
    </div>
</body>
</html>

在頁面的開始部分,使用Layout指定模板頁的地址即可。我們再來看前台顯示效果:

需要注意的是:MVC跟WebForms不同,子頁是先於布局頁被顯示(渲染)出來的。

      b)布局頁的靈活使用(RenderSection)

      有時我們需要頁面的區域內容不是由布局頁定,而是動態的,由子頁自己決定內容的呈現。這時就使用到了RenderSection。比如我們在布局頁TestLayout.cshtml加入以下代碼:

    <div id="menu">
        <!--讓子頁決定如何呈現menu-->
        @RenderSection("menu", false) @*注意此方法跟MVC前版可能不同,false表示可選(非必須)*@
    </div>

再在子頁中加入以下代碼:

    @section menu{
        <ul id="subMenu">
            <li>Item1</li>
            <li>Item2</li>
        </ul>
    }

前台顯示效果:

 

總結

本文主要對Razor的創立,Razor和WebForms視圖引擎的對比做了簡單介紹;同時詳細介紹了Razor的語法。在下一章中,將介紹MVC5頁面之間的傳值,敬請期待~

希望本文對你有幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM