1. 程式人生 > >ASP.NET Core 2 學習筆記(十)視圖

ASP.NET Core 2 學習筆記(十)視圖

部分 合成 cati 分享 col script text var AC

ASP.NET Core MVC中的Views是負責網頁顯示,將數據一並渲染至UI包含HTML、CSS等。並能痛過Razor語法在*.cshtml中寫渲染畫面的程序邏輯。
本篇將介紹ASP.NET Core MVC的Views。

之前 ASP.NET Core 2 學習筆記(六)MVC 有稍微介紹到Views及Controller的對應關系,這邊就不重復說明。

Razor 語法

ASP.NET Core MVC的Views默認是使用Razor引擎,Views的擴展名是用*.cshtml。文件內容以HTML為主,但可以通過@Razor語法寫C#程序。可以假想一下*.cshmtl就是一般的HTML,而Razor語法是C#程序跟靜態HTML溝同的媒介。

@就是Razor語法最重要的溝同媒介,在C#變量前面加上@,就可以將C#程序混合成HTML輸出。如果要在HTML顯示@符號的話,可以連用兩個@符號,就可以把@輸出,範例如下:

<div>@@DateTime.Now @DateTime.Now</div>
<div>
    @@(DateTime.Now - TimeSpan.FromDays(7)) 
    @(DateTime.Now - TimeSpan.FromDays(7))
</div>

實際輸出的HTML 結果:

<div>@DateTime.Now 2018-06-04 10:32:38</div>
<div>
    @(DateTime.Now - TimeSpan.FromDays(7)) 
    2018-05-28 10:32:38
</div>

控制結構(Control Structures)

如果有需要也可以在Views寫C#代碼,通過@{ }定義程式區塊,便可以在Views中寫C#程序,如下:

也可以在循環、判斷式或C#區塊的關鍵字前加上@表示程序區塊,如:@if@switch@for@foreach@while@do{ }while()@try@using@lock
範例如下:

@{
    bool flag = true;
    int number = 3;
}

@if(flag)
{
  <div>flag is true</div>
} 
else
{
  <div>flag is false</div>
}

@switch(number)
{
    case 3:
        <div>number is lucky 3!!!!</div>
        break;
    default:
        <div>number is @number</div>
        break;
}

@for(var i = 0; i < number; i++)
{
    <div>For sample: @i</div>
}

@try
{
    throw new Exception("something wrong");
}
catch(Exception ex)
{
    <div>@ex.Message</div>
}

輸出畫面:

技術分享圖片

指令(Directives)

Razor Views 會被Razor 引擎動態轉換成Class,所以也有些類似C# Class 的方法可以使用。

  • @using
    同C# Class的using,載入不同namespaces,簡化使用時的名稱。例:

@using System.IO
@{
    var dir = Directory.GetCurrentDirectory();
}
<p>@dir</p>
  • @model
    用來綁定Controller傳來的Model類型,並填入Model屬性中,在Views中就可以通過Model取得Controller傳來的Model。例:

@using MyWebsite.Models
@model UserModel
Hello~ 我是 @Model.Name
  • @inherits
    讓Razor View繼承其他自定義的RazorPage類型。例:
    CustomRazorPage.cs

using Microsoft.AspNetCore.Mvc.Razor;

public abstract class CustomRazorPage<TModel> : RazorPage<TModel>
{
    public string CustomText { get; } = "CustomRazorPage.CustomText";
}

  Sample.cshtml

@using MyWebsite.Utils

@inherits CustomRazorPage<TModel>
<div>Custom text: @CustomText</div>
  • @inject
    將DI容器的Service註入至Razor View使用。
    (DI可以參考這篇:ASP.NET Core 2 學習筆記(四)依賴註入 )

  • @functions
    在Razor View 定義方法。例:

@functions {
    public string GetHello()
    {
        return "Hello";
    }
}
<div>From method: @GetHello()</div>
  • @section
    配合Layout 排版使用,下面會介紹。

Layout

通常網站的頁面都有類似的風格,可能只有部分的內容會不一樣,這種清況很適合用Layout。
以下圖為例,網站的每頁都會有Header及Footer而且都長的一樣,就只有Content會不同。

技術分享圖片

通常Layout都會放在Views\Shared資料夾,建立一個_Layout.cshtml

Views\Shared\_Layout.cshtml

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    @RenderSection("styles", required: false)
</head>
<body>
    <header>
        Layout Header
    </header>
    <div>
        <h1>@ViewBag.Title</h1>
        @RenderBody()
    </div>
    <footer>
        Layout footer
    </footer>
    @RenderSection("scripts", required: false)
</body>
</html>

在要套用Layout 的Views,指派要套用的Layout 名稱,如下:

Views\Home\Index.cshtml

@using MyWebsite.Models
@model UserModel
@{
    Layout = "_Layout";
    ViewBag.Title = "Sample";
}

<div>Hello~ 我是 @Model.Name</div>

@section styles {
  <link rel="stylesheet" type="text/css" href="/css/theme.css">
}
@section scripts {
  <script type="text/javascript" src="/js/jquery.js"></script>
} 
  • Layout
    Layout是指定要套用Layout的名稱,預設會在文件夾Views\Shared尋找{Layout 名稱}.cshtml
    也可以指定完整路徑,如:Layout = "/Views/Shared/_Layout.cshtml"
  • ViewBag
    ViewBag是Dynamic類型的對象,可以在同一個Request中,跨Controller及Views存取數據。
  • @section
    在使用Layout時,並不一定會將Razor View全部填入至RenderBody,可能會有需求將某些內容填入至Layout的其他地方。如:*.css的引用填入至<head></head>中;*.js的引用填入至</body>之前。

當打開http://localhost:5000/home/index時,Razor引擎會將Index.cshtml的結果都填入Views\Shared\_Layout.cshtml@RenderBody()
實際輸出的HTML結果:

<!DOCTYPE html>
<html>
<head>
    <title>Sample</title>
    
  <link rel="stylesheet" type="text/css" href="/css/theme.css">

</head>
<body>
    <header>
        Layout Header
    </header>
    <div>
        <h1>Sample</h1>
        
<div>Hello~ 我是 SnailDev</div>


    </div>
    <footer>
        Layout footer
    </footer>
    
  <script type="text/javascript" src="/js/jquery.js"></script>

</body>
</html>

_ViewImports

上例Views\Home\Index.cshtml有用到@using MyWebsite.Models,實務上可能每個Razor View都會用到@using MyWebsite.Models,如果每個*.cshtml都加上這行就會顯得有點笨拙。
可以通過_ViewImports.cshtml把通用性的@using都加到這邊,如此一來就可以套用到全部的Razor View,如:

Views\_ViewImports.cshtml

@using System.IO
@using System.Collections.Generic
@using MyWebsite
@using MyWebsite.Models

如此一來就能將Views\Home\Index.cshtml第一行的@using MyWebsite.Models移除。

_ViewStart

指定Layout也會有套用全部Razor View的需求,可以通過_ViewStart.cshtml,在Razor View的第一個渲染事件指派預設Layout,如:

Views\_ViewStart.cshtml

@{
    Layout = "_Layout";
}

Partial Views

有些重復性很高的畫面,如果散落在各個Razor View,在維護上就會比較麻煩。
可以通過Partial Views把重復的內容變成組件,再重復使用。範例如下:

Controllers\HomeController.cs

// ...
public class HomeController : Controller
{
    public IActionResult Index(int id)
    {
        return View(new List<UserModel>()
        {
            new UserModel()
            {
                Id = 1,
                Name = "John",
                Email = "[email protected]",
            },
            new UserModel()
            {
                Id = 2,
                Name = "Blackie",
                Email = "[email protected]"
            },
            new UserModel()
            {
                Id = 3,
                Name = "Claire",
                Email = "[email protected]"
            }
        });
    }
}

Views\Home\_UserInfo.cshtml

@model UserModel
<div>
    <label>Id:</label>@Model.Id <br />
    <label>Name:</label>@Model.Name <br />
    <label>Email:</label>@Model.Email <br />
</div>

Views\Home\Index.cshtml

@model List<UserModel>
@{
    ViewBag.Title = "User List";
}

@foreach(var user in Model)
{
    @Html.Partial("_UserInfo", user)
    <hr />
}

實際輸出的HTML 結果:

<!DOCTYPE html>
<html>
<head>
    <title>User List</title>
</head>
<body>
    <header>
        Layout Header
    </header>
    <div>
        <h1>User List</h1>
        <div>
            <label>Id:</label>1 <br />
            <label>Name:</label>John <br />
            <label>Email:</label>[email protected] <br />
        </div>
        <hr />
        <div>
            <label>Id:</label>2 <br />
            <label>Name:</label>Blackie <br />
            <label>Email:</label>[email protected] <br />
        </div>
        <hr />
        <div>
            <label>Id:</label>3 <br />
            <label>Name:</label>Claire <br />
            <label>Email:</label>[email protected] <br />
        </div>
        <hr />
    </div>
    <footer>
        Layout footer
    </footer>
</body>
</html>

後記

Views的渲染過程都還是在Server端,所以可以通過Razor寫C#代碼。
Razor引擎最終會將渲染的結果以HTML的方式回傳給Client。
回顧 ASP.NET Core 2 學習筆記(六)MVC 數據流動畫:

技術分享圖片

要註意的是,Razor 的渲染是耗用Server 的CPU 資源,如果有多筆的數據通過循環產生HTML,也會變成網路傳輸的負擔。如果要註重性能,建議用Single Page Application(SPA) 的方式取代Razor。

參考

Views in ASP.NET Core MVC
Razor syntax for ASP.NET Core
Partial Views

老司機發車啦:https://github.com/SnailDev/SnailDev.NETCore2Learning

ASP.NET Core 2 學習筆記(十)視圖