1. _Layout.cshtml 佈局頁 佈局視圖和我們在Asp.Net MVC一樣,佈局視圖_Layout.cshtml使得所有視圖保持一致的外觀變得更加容易,因為我們只有一個要修改的佈局視圖文件,更改後將立即反映在整個應用程式的所有視圖中。 在 ASP.NET Core MVC 中,有一些視圖 ...
佈局視圖和我們在Asp.Net MVC一樣,佈局視圖_Layout.cshtml使得所有視圖保持一致的外觀變得更加容易,因為我們只有一個要修改的佈局視圖文件,更改後將立即反映在整個應用程式的所有視圖中。
在 ASP.NET Core MVC 中,有一些視圖文件,如佈局的視圖,ViewStart.cshtml 和ViewImports.cshtml 等其他.cshtml 文件的文件名以下劃線開頭,這些文件名中的前下劃線表示這些文件不是直接面向瀏覽器。
我們可以在單個應用程式中包含多個佈局視圖文件。比如一個佈局視圖文件服務為管理員用戶,另外一個不同的佈局視圖文件服務於普通用戶。
我們一般將佈局視圖建在Views/Shared文件夾下,以_Layout.cshtml命名。
-
@RenderBody()
是註入視圖特定內容的位置。例如,如果使用此佈局視圖呈現 index.chtml 視圖,則會在我們 調用@RenderBody()方法 的位置註入 index.cshtml 視圖內容
-
IsSectionDefined("Scripts")
判斷子視圖中是否定義了Scripts Section 模塊, 假設有子視圖中index.cshtml 定義如下:
@{ ViewData["Title"] = "Home Page"; } <form method="get" action="/home/query"> <label for="username">姓名:</label><input name="username" id="username"/> <label for="studentNo">學號:</label><input name="studentno" id="studentNo"/> <input type="submit" value="查詢"/> <a href="/home/download">下載文件</a> </form> <!--Scripts section--> @section Scripts{ <script> $('form').submit(function (){ $.get('/home/query',$(this).serialize(),function (data){ console.log(data); }); return false; }); </script> }
此時子視圖中已經定義了
@section Scripts
,那麼_Layout.cshtml 中的 IsSectionDefined("Scripts") 結果為true
-
@RenderSection("Scripts", false);
name: Scripts 表示 section 的名稱
required: false 表示在子視圖中,Scripts section 並不是必要的
它的功能與RenderBody() 類似,同樣是將子視圖中的
@section Scripts
中的內容註入到_Layout.cshtml 中的@RenderSection("Scripts", false)
位置
2. _ViewStart.cshtml 視圖
一盤位於 ~/Views/_ViewStart.cshtml
位置 ,表示對Views
文件夾下的所有視圖文件起作用。可以將所有子視圖中公共的部分放在其中。
作用:所有的視圖請求都會先執行_ViewStart.cshtml。
@{ Layout = "_Layout"; // 如果子視圖不指定佈局視圖,則預設為"_Layout.cshtml" } @if (ViewData["Layout"]!=null && ViewData["Layout"].Equals("Admin")) { Layout = "_AdminLayout"; } else { Layout = "_Layout"; }
_AdminLayout.cshtml 佈局頁代碼:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <title>title</title> </head> <body> <div> <h1>_AdminLayout.cshtml 視圖佈局頁</h1> @RenderBody() </div> </body> </html>
子視圖代碼:
public ViewResult Index() { ViewData["Layout"] = "Admin"; return View(); } <div> <h1>大家好,歡迎來到任我行碼農場,Asp.net Mvc</h1> @if (true) { <h1>hello</h1> } else { <p>world</p> } <h1>我的姓名:@Context.Session.GetString("user")</h1> </div>
運行結果:
3. _ViewImport.cshtml 命名導入視圖
如果我們在很多頁面都使用同一個命名空間,同一個model的話,我們可以在Views/_ViewImports.cshtml文件中添加共用的命名空間,model。
@using StudentManagement.Models; @using StudentManagement.ViewModels; @*還支持以下指令*@ @* @addTagHelper @removeTagHelper @tagHelperPrefix @model @inherits @inject *@
需要註意的是,ViewStart和ViewImports是支持分層的,除了將它放在 Views 文件夾中之外,我們還可以在 Views 文件夾的“Home”子文件夾中放置另一個_ViewImports,在文件 Home 的文件夾中的\_ViewImports
將覆蓋在 Shared 文件夾中的\_ViewImports
文件指定的設置。
4. 標簽助手
標簽助手是服務端代碼能夠參與在 Razor 文件中創建和呈現HTML元素。例如,內置的 ImageTagHelper 可以將版本號追加到圖像名稱。無論何時更改圖像,伺服器都會為圖像生成新的唯一版本,因此可以保證客戶端獲取當前圖像(而不是過時的緩存圖像)。內置的標簽助手多用於常見任務,例如創建表單,鏈接和載入資源等。標簽助手是在 C# 中定義的,它們基於元素名稱,屬性名稱或父標簽來定位HTML元素。例如,當應用 LabelTagHelper 特性時,內置的 LabelTagHelper 可以減少 Razor 視圖中 HTML和 C# 之間的顯示轉換。
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
上面的代碼使用通配符語法(“ * ”)來指定程式集中的所有標簽助手將可用於Views目錄或子目錄中的每個視圖文件。@addTagHelper 之後的第一個參數指定要裝載的標簽助手,第二個參數 “Microsoft.AspNetCore.Mvc.TagHelpers
” 指定包含標簽助手的程式集。
1. 表單標簽助手
Microsoft.AspNetCore.Mvc.TagHelpers 是內置的 ASP.NET Core 標簽助手的程式集。
@model MvcDemo1.Student @{ ViewBag.Title = "title"; Layout = "_Layout"; } <h2>添加學生信息</h2> <form asp-controller="Student" asp-action="Submit" method="post"> <table class="table table-bordered" style="width: 500px;margin: auto"> <tr> <td colspan="3"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> </td> </tr> <tr> <td> <label asp-for="Account"></label> </td> <td> <input asp-for="Account" class="form-control"/> </td> <td> <span asp-validation-for="Account" class="text-danger"></span> </td> </tr> <tr> <td> <label asp-for="Password"></label> </td> <td> <input asp-for="Password" class="form-control"/> </td> <td> <span asp-validation-for="Password" class="text-danger"></span> </td> </tr> <tr> <td> <label asp-for="ConfirmPassword"></label> </td> <td> <input asp-for="ConfirmPassword" class="form-control"/> </td> <td> <span asp-validation-for="ConfirmPassword" class="text-danger"></span> </td> </tr> <tr> <td> <label asp-for="Hobby"></label> </td> <td colspan="2"> <input type="checkbox" name="Hobby" value="編程"/> 編程 <input type="checkbox" name="Hobby" value="學習"/> 學習 <input type="checkbox" name="Hobby" value="爬山"/> 爬山 </td> </tr> <tr> <td><label asp-for="Gender"></label></td> <td colspan="2"> <input type="radio" name="Gender" value="男"/> 男 <input type="radio" name="Gender" value="女"/> 女 </td> </tr> <tr> <td> <label asp-for="Province"></label> </td> <td colspan="2"> <select asp-for="Province" class="form-control" asp-items="ViewBag.ProvinceList"></select> </td> </tr> <tr> <td> <label asp-for="Birthday"></label> </td> <td > <input asp-for="Birthday" class="form-control" /> </td> <td><span asp-validation-for="Birthday"></span></td> </tr> <tr> <td> <label asp-for="Description" ></label> </td> <td colspan="2"> <textarea asp-for="Description" class="form-control"></textarea> </td> </tr> <tr> <td colspan="3"> <input type="submit" class="btn btn-primary" value="提交"/> </td> </tr> </table> </form> @section Scripts { <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script> <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script> } public class Student { [Display(Name = "賬號")] [Required(ErrorMessage = "請輸入賬號")] public String? Account { get; set; } [Display(Name = "密碼")] [DataType(DataType.Password)] [Required(ErrorMessage = "請輸入密碼")] public String? Password { get; set; } [Display(Name = "確認密碼")] [DataType(DataType.Password)] [Compare("Password",ErrorMessage = "兩次輸入的密碼不一致")] public String? ConfirmPassword { get; set; } [Display(Name = "愛好")] public String[]? Hobby { get; set; } [Display(Name = "性別")] public String? Gender { get; set; } [Display(Name = "祖籍")] [Required(ErrorMessage = "請選擇祖籍")] [Range(1,int.MaxValue,ErrorMessage = "請選擇祖籍")] public int Province { get; set; } [Display(Name = "生日")] [DataType(DataType.Date)] [Required(ErrorMessage = "請選擇你的生日")] public DateTime Birthday { get; set; } [Display(Name = "簡介")] public string? Description { get; set; } } public record Province(int Id, String Name); public IActionResult Create() { List<Province> provinces = new() { new(0, "請選擇"), new(1, "江西"), new(2, "北京"), new(3, "臺灣") }; // 創建一個下拉框數據源 ViewBag.ProvinceList = new SelectList( provinces, // 下拉框的數據源 "Id", // 選中值設置為Id 屬性 "Name" // 顯示項設置為Name屬性 ); return View(); } [HttpPost] public IActionResult Submit(Student student) { if (ModelState.IsValid) { var entity = Students.FirstOrDefault(p => p.Account!.Equals(student.Account)); if (entity != null) { // 服務端用於邏輯處理產品的錯誤 key 需要為空 ModelState.AddModelError("", "賬號已經存在"); return View("Create"); } Students.Add(student); return Ok("添加成功"); } return BadRequest("請求失敗"); }
-
asp-validation-summary
只能用於div 標簽中,來至於
ValidationSummaryTagHelper
,其中的ValidationSummary
中包含了三個枚舉值:-
All : 顯示所有的錯誤信息
-
ModelOnly : 只顯示Model級別的錯誤信息(不包括所有的屬性錯誤)
-
None: 不顯示錯誤信息,一般用不上
-
-
asp-validation-for
用於顯示屬性的錯誤信息,只能用於span標簽中
-
SelectList
專用於綁定下拉框數據源,也可以直接綁定一個枚舉
enum OrderState{ WaitPay, WaitSend, WaitReceive, Finish, Cancel } <select asp-for="OrderState" asp-items="@Html.GetEnumSelectList<OrderState>()"></select>
2. LinkTagHelper
應用在link元素上,支持備用的樣式文件。它具有以下屬性:
-
href——指定樣式資源的鏈接地址。
-
asp-href-include——指定所有需要被載入的樣式文件路徑,當有多個時,以逗號來分隔每一個;這裡的路徑是相對於應用程式中wwwroot的相對路徑。
-
asp-href-exclude——指定那些不需要被載入的樣式文件路徑,當有多個時,以逗號來分隔每一個;這裡的路徑是相對於應用程式中wwwroot的相對路徑。
-
asp-fallback-href——指定備用資源鏈接地址。
-
asp-fallback-href-include——指定所有需要被載入的備用樣式文件路徑,當有多個時,以逗號來分隔每一個;這裡的路徑是相對於應用程式中wwwroot的相對路徑。
-
asp-fallback-href-exclude——指定那些不需要被載入的備用樣式文件路徑,當有多個時,以逗號來分隔每一個;這裡的路徑是相對於應用程式中wwwroot的相對路徑。
-
asp-fallback-test-class——用來檢測載入失敗的樣式名。
-
asp-fallback-test-property——用來檢測資源載入失敗所用的測試屬性。
-
asp-fallback-test-value——用來檢測資源載入失敗所用的測試值。
-
asp-file-version——bool值,用來指定是否需要將文件版本信息加入到url地址中。
例如,在下麵例子中,當從網路上(http://ajax.aspnetcdn.com/ajax/bootstrap-touch-carousel/0.8.0/css/bootstrap-touch-carousel.css)載入樣式文件失敗時,載入本地相應的樣式文件(~/lib/bootstrap-touch-carousel/css/bootstrap-touch-carousel.css)。通過檢測樣式類carousel-caption中display屬性是否是none來判斷網路上樣式文件是否載入成功。
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.1/css/bootstrap.min.css" asp-fallback-href-include="~/lib/bootstrap/dist/css/bootstrap.css" asp-fallback-test-class="alert-warning" asp-fallback-test-property="color" asp-fallback-test-value="#664d03" />
3. EnvironmentTagHelper
應用在environment元素上,根據不同names的設置呈現不同的內容。它支持以下屬性:
-
names——指定環境名,當有多個時候以逗號分隔。這裡判斷的依據是,讀取IHostingEnvironment的EnvironmentName的值,與environment元素中的names匹配,當匹配上的時候就呈現出裡面的內容,否則移除該environment元素。
在很多情況下,我們想在開發環境使用一套配置信息,在生產環境又是另外一套,這時候就需要使用條件判斷語句了,不過在新版的MVC中,使用EnvironmentTagHelper提供的Environment元素標簽就可以了,示例如下:
<environment names="Development"> <link rel="stylesheet" href="~/lib2/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="~/css/site.css" /> </environment> <environment names="Staging,Production"> <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css" asp-fallback-href="~/lib2/bootstrap/dist/css/bootstrap.min.css" asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /> <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /> </environment>
在上述代碼中,我們定於,如果是Development環境就使用本地的js文件,否則(Staging或Production環境)就使用網路上的css文件。asp-append-version="true"為靜態文件提供唯一版本號。
4. ScriptTagHelper
應用在script元素上,和LinkTagHelper一樣,它也具有fallback功能, 只不過這裡判斷的不是class樣式,而是用來判斷預設的js文件是否載入成功。
它支持以下屬性:
src指定要載入的js源地址。
asp-src-include指定要載入的js文件,當有多個文件時以逗號分隔。這裡文件路徑是相對於程式webroot的相對路徑。
asp-src-exclude指定不需要載入的js文件,當有多個文件時以逗號分隔。這裡文件路徑是相對於程式webroot的相對路徑。
asp-fallback-src指定備用的js源地址。
asp-fallback-src-include指定需要載入的備用js文件,當有多個文件格式時以逗號分隔。這裡文件路徑是相對於程式webroot的相對路徑。
asp-fallback-src-exclude指定不需要載入的備用js文件,當有多個文件時以逗號分隔。這裡文件路徑是相對於程式webroot的相對路徑。
asp-file-version——bool值,用來指定是否需要將文件版本信息加入到url地址中。
<script src="//ajax.aspnetcdn.com/ajax/jquery/jquery-1.10.2.min.js" asp-fallback-src="~/lib/jquery/jquery.min.js"> </script>
此外,還可以根據需要自定義TagHelper。
5. 局部視圖
<partial name="局部視圖名" for="局部視圖數據源"/>
5. 自定義標簽助手
-
所有的標簽助手都繼承於
TagHelper
類,類名都以TagHelper命名結尾,例如:TableListTagHelper -
重寫Process 方法
-
using Microsoft.AspNetCore.Razor.TagHelpers; namespace MvcDemo.Util; [HtmlTargetElement("email")] public class EmailTagHelper:TagHelper { // 想要生成的目標html <a href="mailto:[email protected]">[email protected]</a> /// <summary> /// 郵箱地址屬性 /// </summary> public string? EmailTo { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "a"; // 將email 標簽替換成a標簽 output.Attributes.SetAttribute("href",$"mailto:{EmailTo}"); // 設置a 標簽屬性 output.Content.SetContent(EmailTo); // 設置a 標簽中間內容 } }
TagHelperContext: 包含了當前執行的TagName 標簽元素相關的信息
-
TagHelperOutput:包含了即將生成的html相關信息。
-
[HtmlTargetElement("email")] 表示目標標簽名叫"Email"
-
[HtmlTargetElement(Attributes = "email")] 表示此標簽只能作為一個名叫email的屬性標簽
-
-
在_ViewImport.cshtml 中將 TableListTagHelper 類的程式集通過@addTagHelper 指令將自定義的標簽助手導入進來。當前我的程式集名稱是:
MvcDemo
, 我的tagHelper類是在MvcDemo.Utils
命名空間里。@addTagHelper *,MvcDemo // 導入自定義的標簽助手的程式集
-
在Razor視圖中使用
-
假設你的自定義標簽助手名叫:
EmailTagHelper
,那麼視圖中寫成如下:<email></email>
本例中,EmailTagHelper中有個EmailTo 屬性,那麼我們應該寫成:
<email email-to="[email protected]"></email>
註意屬性名單詞與單詞間用“-”隔開,單詞全部小寫。
-
假設你的定義標簽助手名叫:
TableListTagHelper
,那麼視圖中寫成如下:<table-list></table-list>
-
6. TagHelper 首碼
隨著現在前端框架越來越豐富多彩,如果自定義tagHelper 太多,或許你的tagHelper 會與某些前端控制項衝突了。
此時我們可以利用TagHelper 首碼
來幫忙解決這個問題(只針對當前頁面有效)
@tagHelperPrefix "renwoxing:" // 只針對當前頁面有效 <div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p> </div> <renwoxing:email email-to="[email protected]"></renwoxing:email> <a> 沒有用到自定義標簽,不需要加首碼</a> <renwoxing:a asp-action="Privacy">Privacy</renwoxing:a>
我們通過會在首碼尾部加一個冒號,以免與其他標簽連在一起了。
一旦加了標簽首碼,則所有用到了標簽助手的地方,都需要加上首碼。
5. ViewComponent 視圖組件
視圖組件與分部視圖類似,但它們的功能更加強大。 視圖組件不使用模型綁定,具體取決於調用視圖組件時傳遞的數據。 本文是使用控制器和視圖編寫的,但視圖組件使用
視圖組件:
-
呈現一個區塊而不是整個響應。
-
包括控制器和視圖間發現的相同關註點分離和可測試性優勢。
-
可以有參數和業務邏輯。
-
通常從佈局頁調用。
視圖組件適用於任何對於部分視圖來說過於複雜的可重用呈現邏輯,例如:
-
動態導航菜單
-
標記雲,在其中查詢資料庫
-
登錄面板
-
購物車
-
最近發佈的文章
-
博客上的邊欄內容
-
將在每個頁面上呈現的登錄面板,並顯示註銷或登錄的鏈接,具體取決於用戶的登錄狀態
視圖組件由兩個部分組成:
-
類,通常派生自