MVC 中的 View 就與前端密切相關,這個章節要來介紹 ASP.NET MVC 中的 View

透過樣板引擎(template engine),將轉換成 HTML 的頁面,回傳給瀏覽器供顯示

View 的類型

View 的副檔名是 .cshtml(或 .vbhtml

View 的種類可分為幾種:

  • View:action 回傳 ViewResult
  • Partial View:action 回傳 PartialViewResult,習慣上的命名會是底線開頭、partial 結尾
  • Layout:一個組成頁面的共用樣板,像是 Header、Menu、Footer 會在其中,container 元件的概念。利用 RenderSectionRenderBody 等方法,在 layout 裡面插入 slot 已供使用的時候,置入想要的 Partial View template
  • Template:可以說是比 Partial View 更小的規模。分為 DisplayTemplate 與 EditorTemplate 兩種類型,前者用於檢視、後者用於編輯的頁面

獲得資料的方法

View 經常是一個被動的角色,Controller 執行完畢,準備好提供給 View 的 Model,調用特定的 View 以 HTML 解釋這份資料

方式優點缺點
Model強型別,得以藉編譯期間進行型別檢查當以 string 型別作為 View Model 時會有一點點小麻煩
ViewData不需要建立 View Model 類別即可傳遞資料弱型別,無編譯期間型別檢查
ViewBag不需要建立 View Model 類別即可傳遞資料弱型別,無編譯期間型別檢查
TempData不需要建立 View Model 類別即可傳遞資料,可以跨 Action 傳遞弱型別,無編譯期間型別檢查

View Engine 概觀

View Engine 隱藏在 Action 與 View 之間,當回傳 ViewResult(或 PartialViewResult)後,ActionInvoker 呼叫 ExecuteResult 方法,啟動 View Engine 來工作

View Engine 有兩種實作,WebForm View Engine 與 Razor View Engine,在 Controller 的章節已有提到

除了上述兩種內建的 View Engine 之外,網路上也有開源社群提供的多種 View Engine,像是:Spark View Engine、JsViewEngine、FreeMarker.NET、BLADE View Engine、NHaml、Aurora View Engine、XsltViewEngine⋯⋯ 等

使用第三方的 View Engine,除了用 NuGet 安裝第三方套件之外,還要在 Global.asax 的 Application_Start 方法底下註冊後方可使用

Razor 語法

這裡列出 Razor 的一些基本語法與書中範例,同時對照著前端三大框架的相對應寫法

程式碼區塊 Code Block

@{
  int val = 10;
  string message = "hello";
}

React

在 function 裡面,與 jsx 分離

Vue

<script> 裡面,與 <template> 分離

Angular

@component class 裡面,與 html 分離

陳述式 Expression

<span>@message</span>

<span>@Html.Raw(message)</span>

React

<span>{message}</span>

Vue, Angular

<span>{{message}}</span>

結合程式與標記語言

@foreach(var item in items)
{
  <span>@item.Property</span>
}

React

{items.map((item) => <span key={item.property}>{item.property}</span>)}

Vue

<span v-for="item in items">{{ item.property }}</span>

Angular

<span *ngFor="let item of items">{{ item.property }}</span>

混合程式與文字

// 1
@if(condition)
{
  <text>Plain text</text> @condition
}

// 2
Hello, my name is @name

//3
@if(condition)
{
  @:Plain text @condition
}

React

{condition && <p>hello world</p>}

Vue

<p v-if="condition">hello world</p>

Angular

<p *ngIf="condition">hello world</p>

using 區塊

@using(Html.BeginForm())
{
  <input type="submit" value="Submit" />
}

Email

hi someone@microsoft.com

@ 符號(跳脫字元)

<div>show @@ mark on razor template</div>

三大框架的部分,因為語法的緣故,比較要注意的大概是 ><{} 這四種符號的跳脫方式

React

在 jsx 中需要跳脫的字元,像是:><{},可轉換成 HTML code 的寫法:&gt;&lt;&#123;&#125;,或用括號包成字串的方式處理

// error
<div><></div>
// solution
<div>{"<>"}</div>
<div>&lt;&gt;</div>

// error
<div>{}</div>
<div>{{}}</div>
// solution
<div>&#123;&#125;</div>
<div>{"{{}}"}</div>

// error
<div>{{greeting}}</div>
// solution
<div>{`{${greeting}}`}</div>
<div>&#123;{greeting}&#125;</div>

Vue

HTML code 在使用 &gt;&lt; 沒什麼問題,但兩層的 &#123;&#125;(也就是 {{ }})扔會出現錯誤, 簡單的做法就是用 <span> 包起來:

<!-- error -->
<div><></div>
<div>{{"<>"}}</div>
<!-- solution -->
<div>&lt;&gt;</div>

<!-- ok -->
<div>{}</div>
<div>{{}}</div>

<!-- error -->
<div>{{{{greeting}}}}</div>
<div>{{`{{${greeting}}}`}}</div>
<div>{{`&#123;&#123;${greeting}&#125;&#125;`}}</div>
<div>&#123;&#123;{{greeting}}&#125;&#125;</div>
<!-- solution -->
<div><span>&#123;&#123;</span>{{greeting}}<span>&#125;&#125;</span></div>

Angular

Angular 可以直接在 template 使用 ><,當然 &gt;&lt; 也是沒問題; 括號的部分同樣用字串來處理;變數與括號的混合,則同 Vue 用 <span> 隔開

<!-- ok -->
<div><></div>

<!-- error -->
<div>{}</div>
<div>{{}}</div>
<!-- solution -->
<div>{{"{}"}}</div>
<div>{{"{{}}"}}</div> 

<!-- error -->
<div>{{{greeting}}}</div>
<div>{{`{{${greeting}}}`}}</div>
<div>{{`{${greeting}}`}}</div>
<div>&#123;{{greeting}}&#125;</div>
<div><span>{</span>{{greeting}}<span>}</span></div>
<!-- solution -->
<div><span>&#123;</span>{{greeting}}<span>&#125;</span></div>
<div><span>&#123;&#123;</span>{{greeting}}<span>&#125;&#125;</span></div>

註解

@*
  多行註解
  ⋯⋯
*@

@* 單行註解 *@

React

{/* hello this is comment */}
{/* 
  comment 1
  comment 2
  ...
*/}

Vue, Angular

<template>
  <!-- this is comment -->
</template>

Func 委派

@{
  Func<string, object> strongify = @<strong>@item</strong>
}

@strongify("John")

React

const strongify = (text) => <strong>{text}</strong>;

{ strongify("John")}

用傳入 props 的方式實作

Vue, Angular

同樣利用 component 傳入 props 的方式來實作

Helpers

主要有三種 Helper 可以使用:UrlHelper、HtmlHelper、AjaxHelper, 在 View 中,分別使用 Url、Html、Ajax 分別取得這三種 Helper 的執行個體

UrlHelper

  • Action
  • RouteUrl
  • HttpRouteUrl
  • Content
  • Encode
  • IsLocalUrl

最常使用的,大概是 Url.Action 了,用來加在 <a> 的 href 上

HtmlHelper

在 View 中最常見的 Helper,可大致分為三類:一般類、表單類、功能類

HtmlHelper 有很大一部分的方法,是倚賴 Model 與 Lambda Expression

一般類

  • Action, RenderAction
  • Partial, RenderPartial:用於插入 Partial View,佷常使用
  • ActionLink
  • RouteLink
  • AntiForgeryToken
  • Encode
  • Raw

表單類

  • BeginForm:製作一個 <form> 的表單區塊
  • BeginRouteForm
  • EndForm
  • TextBox, TextBoxFor
  • Hidden, HiddenFor
  • Password, PasswordFor
  • CheckBox, CheckBoxFor
  • RadioButton, RadioButtonFor
  • DropDownList, DropDownListFor
  • EnumDropDownListFor
  • ListBox, ListBoxFor
  • EditBox, EditBoxFor
  • Label, LabelFor
  • DisplayName, DisplayNameFor
  • DisplayText, DisplayTextFor
  • Display, DisplayFor
  • DisplayForModel
  • Editor, EditorFor
  • EditorForModel
  • ValidationMessage, ValidationMessageFor
  • ValidationSummary

這一類幾乎都是會轉換成表單類 HTML 的 Helper 方法

功能類

  • AttributeEncode
  • Id, IdFor
  • Name, NameFor

AjaxHelper

AjaxHelper 在 HTML 標籤上添加 data-* 屬性,供 unobtrusive 使用,透過 jquery.unobtrusive-ajax.js 讓 HTML 標籤擁有 AJAX 的能力