原文:Layout
作者:Steve Smith
翻譯:婁宇(Lyrics)
校對:孟帥洋(書緣)
視圖(View)經常共享視覺元素和編程元素。在本篇文章中,你將學習如何在你的 ASP.NET 應用程序中使用通用布局視圖、共享指令以及在渲染視圖前運行通用代碼。
章節:
什么是布局視圖
大部分 Web 應用程序在用戶切換頁面時,使用通用布局提供了一致的用戶體驗。通用布局通常包含頁眉、導航欄(或菜單)以及頁腳等通用 UI 元素。
在一個應用程序中,諸如腳本(scripts)和樣式表(stylesheets)這樣的通用 HTML 結構也頻繁的被許多頁面使用。所有的這些共享元素可以在 layout 文件中定義,這樣應用程序中的任何視圖都可以使用它們。布局視圖減少了視圖中的重復代碼,幫助我們遵循 Don't Repeat Yourself (DRY) 原則。
按照慣例,ASP.NET 應用程序的默認布局文件命名為 _Layout.cshtml
。Visual Studio ASP.NET Core MVC 項目模板包含這個布局文件,位置在 Views/Shared
文件夾:
這個布局為應用程序中的視圖定義了一個頂層模版。布局對應用程序來說不是必須的,應用程序也可以定義多個模板供不同的視圖使用。
一個 _Layout.cshtml
例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - WebApplication1</title>
<environment names="Development">
<link rel="stylesheet" href="~/lib/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="~/lib/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>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">WebApplication1</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
</ul>
@await Html.PartialAsync("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© 2016 - WebApplication1</p>
</footer>
</div>
<environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("scripts", required: false)
</body>
</html>
指定布局
Razor 視圖擁有一個 Layout
屬性。各個視圖可以通過設置這個屬性來指定布局:
@{
Layout = "_Layout";
}
指定布局時可以用完整路徑(例如: /Views/Shared/_Layout.cshtml
)或者部分名稱(例如: _Layout
)。當使用部分名稱時,Razor 視圖引擎將使用它的標准發現流程搜索布局文件。首先 Controller 相關的文件夾,其次是 Shared
文件夾。這個發現流程和部分視圖的是完全相同的。
默認情況下,每個布局視圖必須調用 RenderBody
方法。在哪里調用 RenderBody
,視圖內容就會在那里被渲染。
Sections
布局視圖可以通過調用 RenderSection
方法來引用一個或多個 sections (布局視圖不是必須引用 Section)。Section 提供了組織某些頁面元素放置的方法。每一個 RenderSection
調用都可以指定 Secton 是必須還是可選的。如果找不到一個必須的 Section,會拋出異常。個別視圖使用 @section
指定被渲染的內容。如果一個視圖定義了一個 Section,它必須被渲染(否則將會發生錯誤)。(譯者注:這里的必須被渲染指必須通過 RenderSection
方法調用。)
一個在視圖中定義 @section
的例子:
@section Scripts {
<script type="text/javascript" src="/scripts/main.js"></script>
}
在上面的代碼中,將驗證腳本添加到一個包含 Form 表單的視圖中的 scripts
Section 中。其它在同一個應用程序的視圖也許不需要任何額外的腳本,所以不需要定義 scripts
Section。
定義在視圖中的 Section 只在其相關的布局頁中可用。它們不能在局部視圖、視圖組件或視圖系統的其他部分中引用。(譯者注:Section 可以在任何視圖系統中定義,但只能在布局視圖中調用 RenderSection 進行渲染。)
忽略 Section
默認情況下,內容頁中 Body 和所有 Section 都必須在布局頁中渲染。Razor 視圖引擎通過跟蹤 Body 和每個 Section 是否被渲染來強制執行。
如果需要指示視圖引擎忽略 Body 和 Section,調用 IgnoreBody 和 IgnoreSection 方法。
在 Razor 頁面的 Body 和每個 Section 必須被渲染或忽略。
導入共享指令
視圖可以使用 Razor 指令做許多事,比如導入命名空間或者進行依賴注入。由多個視圖共享的指令可以在公共的 _ViewImports.cshtml
文件中指定。 _ViewImports
文件支持以下指令:
@addTagHelper
@removeTagHelper
@tagHelperPrefix
@using
@model
@inherits
@inject
這個文件不支持其他 Razor 特性,比如 functions 和 section 的定義等等。
一個 _ViewImports.cshtml
文件的例子:
@using WebApplication1
@using WebApplication1.Models
@using WebApplication1.Models.AccountViewModels
@using WebApplication1.Models.ManageViewModels
@using Microsoft.AspNetCore.Identity
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
在ASP.NET Core MVC 應用程序中, _ViewImports.cshtml
通常被放置在 Views
文件夾下。_ViewImports.cshtml
文件也可以放在任何文件夾下面,在這種情況下,它將只作用於該文件夾和其子文件夾下的視圖。在執行順序上,首先執行在根目錄下的 _ViewImports
文件,然后執行視圖所在文件夾下的 _ViewImports
文件,所以在根目錄中 _ViewImports
文件里指定的設定可能會被覆蓋掉。
舉個例子,如果根目錄中 _ViewImports.cshtml
文件指定了 @model
和 @addTagHelper
,另外一個 Controller 相關文件夾下的 _ViewImports.cshtml
文件指定一個不同的 @model
並添加另外一個 @addTagHelper
,視圖將可訪問兩種 TagHelper 並使用后者指定的 @model
。
如果一個視圖中有多個 _ViewImports.cshtml
文件被運行,多個 ViewImports.cshtml
文件中指令的組合行為如下:
@addTagHelper
,@removeTagHelper
:按照順序全部運行@tagHelperPrefix
:離視圖最近的一個覆蓋其他的@model
:離視圖最近的一個覆蓋其他的@inherits
:離視圖最近的一個覆蓋其他的@using
:全部包含; 重復的忽略@inject
:對每一個屬性而言(通過屬性名區分),離視圖最近的一個覆蓋其他的
在視圖之前運行代碼
如果你有代碼需要在每個視圖之前運行,這些代碼應該放在 _ViewStart.cshtml
文件中。按照約定, _ViewStart.cshtml
文件位於 Views
文件夾。 _ViewStart.cshtml
中列出的語句會在所有完整的視圖(不包含布局視圖和部分視圖)之前運行。就像 ViewImports.cshtml ,_ViewStart.cshtml
也有優先級。如果一個 _ViewStart.cshtml
文件定義在 Controller 相關的視圖文件夾內,它將比 Views
文件夾根目錄下的 _ViewStart.cshtml
文件更晚運行(如果根目錄下有這個文件的話)。
一個 _ViewStart.cshtml
文件例子:
@{
Layout = "_Layout";
}
上面的文件指定了所有的視圖將使用 _Layout.cshtml
布局視圖。
注意
通常無論_ViewStart.cshtml
還是_ViewImports.cshtml
都不能放在/Views/Shared
文件夾下。應用程序級別的這些文件,應該直接放在/Views
文件夾下。