iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 24
1

在 MVC 架構中,View 負責將結果呈現給客戶端,通常會產生出 HTML 到瀏覽器端顯示。在 ASP.NET Core MVC 中,使用 Razor 語法來產生 View 結果,副檔名是 .cshtml,顧名思義就是用 C# 編譯產生的 HTML 檔案 XD。視圖檔案會放在 ~/Views 資料夾中,通常會以 Controller 作為資料夾,並用 Action 作為檔案名稱:

https://ithelp.ithome.com.tw/upload/images/20181107/20107875JFf9I9sLRy.png

例如下列這個 MVC 範本產生出的 Controller/Action

public class HomeController : Controller
{
    public IActionResult About()
    {
        ViewData["Message"] = "Your application description page.";

        return View();
    }
}

就會使用 ~/Views/Home/About.cshtml 來產生 HTML 結構。

@{
    ViewData["Title"] = "About";
}
<h2>@ViewData["Title"]</h2>
<h3>@ViewData["Message"]</h3>

<p>Use this area to provide additional information.</p>

@ 符號開頭的是 Razor 語法,可以在大括號 {...} 中撰寫 C# 語法邏輯,或者直接接著變數來把值輸出到 HTML 中。今天不會說明 Razor 語法,想了解的讀者可以參考官方文件

Action 中,可以直接使用 return View() 來讓 MVC 框架選擇對應的視圖,也可以用 return View("path/to/your/view.cshtml") 來指定要使用的視圖檔案。

傳資料給 Views

要由 Controller 傳資料給 View 有幾種方式:

  • 強型別:view model
  • 弱型別
    • ViewData
    • ViewBag

強型別檢視

直接用 @model 來指定這個 View 所使用的類別,在 View 中就可以用 @Model 來取得物件實例的資料。要把強型別的資料傳給 View 的方式,是在 return View() 的時候把物件實例作為參數傳入:

public class TodoController : Controller
{
    public IActionResult Index()
    {
        var todos = _context.Todo.ToList();

        return View(todos);
    }
}

Razor 中就可以這樣來使用強型別的資料:

@model IEnumerable<ironman2018.Models.EntityFramework.TodoModel>

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<table class="table">
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Id)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Title)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.CreatedAt)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Completed)
                </td>
            </tr>
        }
    </tbody>
</table>

弱型別資料

弱型別資料分為 ViewDataViewBag 兩種方式,型別都是在執行期間才會決定,比較不容易除錯,一般都還是以使用強型別為主。

ViewDataViewDataDictionary 類別,類似 Dictionary<string, object> 這樣的資料結構。前面範例中看到的 ViewData["Message"] = "Your application description page."; 就是在 ViewData 中存入一個索引鍵為 Message 的字串,在 View 中以 ViewData["Message"] 來使用。

ViewBagDynamicViewData 類別,這個方式都是使用 dynamic 來傳遞資料,使用方式跟 ViewData 相同,但可以用 . 來取資料。

Layout

通常同一個網站中大部分頁面的配置都類似,為了將不同頁面共用的區塊拉出來方便維護,會使用 Layout 來處理。例如下圖,網頁上方是 Header,下方是 Footer,左側有一塊 Navigation,不同頁面會有差別的只有 Content 的區塊:

https://ithelp.ithome.com.tw/upload/images/20181107/20107875St8eB2tlb0.png

圖片來源:https://docs.microsoft.com/en-us/aspnet/core/mvc/views/layout

一般會將 Layout 的配置檔放在 ~/Views/Shared 目錄中,例如在我們專案中的 ~/Views/Shared/_Layout.cshtml 檔案(節錄部分),不同頁面顯示的內容會由 @RenderBody() 來顯示:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - ironman2018</title>
</head>
<body>
    <!-- 這邊是 Header -->
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                ......
            </div>
            <div class="navbar-collapse collapse">
                ......
            </div>
        </div>
    </nav>

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; 2018 - ironman2018</p>
        </footer>
    </div>
</body>

在個別的 View 中,可以在最上方使用 Layout 屬性來指定要使用的配置,內容就會在配置中的 @RenderBody() 中渲染出來。

@{
    Layout = "_Layout";
}

或者在 ~/Views/_ViewStart.cshtml 中設定專案中共用的配置(語法跟上面一樣)。

部分檢視 Partial Views

有些 HTML 很多的區塊,或者常常重複使用的區塊,可以用部分檢視的方式獨立出來。例如上面的 _Layout 中,如果覺得 Header 內容太多不好維護,可以建立一個 ~/Views/Shared/_HeaderPartial.cshtml,並把 _Layout 修改成:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - ironman2018</title>
</head>
<body>
    <!-- 引用 Header 的部分檢視 -->
    <partial name="_HeaderPartial"/>

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; 2018 - ironman2018</p>
        </footer>
    </div>
</body>

或者在 ~/Views/Todo/Index.cshtml 中,可以把顯示每筆資料的 Razor 獨立成一個強型別的部分檢視 ~/Views/Todo/_ItemPartial.cshtml

@model ironman2018.Models.EntityFramework.TodoModel

<tr>
    <td>
        @Model.Id
    </td>
    <td>
        @Model.Title
    </td>
    <td>
        @Model.CreatedAt
    </td>
    <td>
        @Model.Completed
    </td>
</tr>

同時修改原本的 View

@model IEnumerable<ironman2018.Models.EntityFramework.TodoModel>

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<table class="table">
    <tbody>
        @foreach (var item in Model)
        {
            <partial name="_ItemPartial" model="item"/>
        }
    </tbody>
</table>

如果是有寫過之前 ASP.NET MVC 的讀者可能會疑惑,部分檢視的語法應該是 @Html.Partial("_PartialName") 才對吧?!

這是因為 ASP.NET Core 提供了新的 TagHelper 語法,可以用類似 HTML 的方式來產生結果,這部分就留待明天揭曉吧~

參考資料


上一篇
Model Binding 模型繫結
下一篇
Tag Helpers 標籤輔助程式
系列文
.Net Core 網站開發 10131

尚未有邦友留言

立即登入留言