ASP.NET Core Razor 布局视图
上一章节中我们学习了如何使用 EF 框架从数据库中读取并显示数据,我们使用了两个模板文件 Index.cshtml
和 Detail.cshtml
。相信大家在创建填充 Detail.cshtml
内容的时候会想,为什么 <!DOCTYPE html>
这样重复的内容我们要输入一次又一次,有没有办法只输入一次呢?
答案是肯定的,有的。
Razor 视图引擎提供了 Layout
布局的功能,可以把视图中公共的部分抽出来单独为一个文件,这样就省去了不少的麻烦
本章节,我们就来学习下 Razor 布局视图。大多数网站和 Web 应用程序都会创建具有一些通用元素的页面
- 通常每个页面顶部都有一个区域用于显示公共的 logo 和导航菜单
- 页面的左边侧栏都会添加一些其它的链接和信息,且页面底部都会显示版权信息和一些公司信息
几乎应用程序的每个页面都可能包含这些公共元素。在 ASP.NET Core 中,我们可以使用布局视图来避免一次又一次的重复编写它们
布局视图 ( Layout View )
首先,我们来了解下 ASP.NET Core 中的布局视图到底是什么:
-
布局视图是带有
.cshtml
扩展名的 Razor 视图可以随意给布局视图命名,一般情况下,默认的约定的布局视图名字是
_Layout.cshtml
这是布局视图的通用名称,可以不需要前导下划线。因为这只是许多开发者遵循的一个约定
用来区分布局视图与普通视图
-
布局视图是一种特殊的视图,一旦我们有了布局视图,我们就可以设置我们的控制器视图,如
Home
的Index
视图我们可以将控制器视图设置为在布局视图内的特定位置显示
这种视图布局方法意味着
Index.cshtml
不需要知道有关 logo 或顶级导航的任何信息Index.cshtml
视图只需要显示控制器操提供模型的特定内容,其它内容则由 布局视图来负责处理
范例
我们举一个简单的例子,给我们的 HelloWorld
项目添加一个布局视图
如果我们有多个视图,那么会看到所有的视图都会包含一些重复的标记。比如都有一个 <html>
标签,<head>
标签和 <body>
标签
虽然我们的 HelloWorld
项目中没有导航菜单,但其它应用程序则可能存在,我们并不希望在每个视图中都复制这些相同的标签
现在,我们来创建 Layout 视图
我们会在 Views
目录下新建一个目录 Shared
,然后添加一个布局视图 _Layout.cshtml
从前面的几章节中我们了解到,如果 MVC 框架在控制器目录找不到视图,它们就会尝试在 Shared
目录中查找,也就是说 Shared
目录里的视图可以被多个控制器使用
-
在
Views
目录下新建一个目录Shared
-
右键点击
Shared
目录,选择 添加 -> 新建文件 打开新建文件对话框如果你的电脑是
Windows
系统,则是选择 添加 -> 新建项 -
选中左边的 ASP.NET Core,然后从中间选中 MVC 视图布局页面
如果你的电脑是
Windows
系统,则是先选中 ASP.NET Core -> Web -> ASP.NET ,然后从中间选择 Razor 布局 -
在名称中输入
_Layout
或_Layout.cshtml
( Windows ),然后点击右下角的 新建 或 添加 ( Windows )
创建完成后的目录结果如下
_Layout.cshtml
中默认的内容如下
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> </head> <body> <div> @RenderBody() </div> </body> </html>
因为布局视图也是一个 Razor 视图,所以也可以使用 C# 表达式
在上面的代码中,可以看到像 RenderBody
和 ViewBag.Title
这样的 C# 表达式。
当一个 MVC 控制器方法渲染一个普通的视图时,如果普通的视图有加载一个布局视图。
那么普通视图和它生成的 HTML 片段就会被包含进布局视图中
而被包含的位置,就是 @RenderBody
表达式的地方,也就是说 @RenderBody
表达式用于包含普通视图生成的内容
布局视图中的其它表达式,例如 @ViewBag.Title
,ViewBag
是一种数据结构,可以添加任何想要放入 ViewBag
的属性或数据。
例如可以在 ViewBag
上添加 ViewBag.Title
,ViewBag.CurrentDate
或我们想要的任何属性
我们修改下 _Layout.cshtml
文件,添加一个当前的时间
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> </head> <body> <div>@DateTime.Now</div> <div> @RenderBody() </div> </body> </html>
接下来我们回到 Home/Index.html
普通控制器视图,它的原本内容如下
@model HelloWorld.Controllers.HomePageViewModel <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Home 控制器下的 Index 方法</title> </head> <body> <h1>欢迎!</h1> <div>这个消息来自 Home 控制器下的 Index 的视图文件 index.cshtml </div> <table> @foreach (var employee in Model.Employees) { <tr> <td><a href="/Home/Detail/@employee.ID">@employee.ID</a></td> <td>@employee.Name</td> </tr> } </table> </body> </html>
有了布局视图,我们就可以删除所有我们不在需要的 HTML 标签,比如 <!DOCTHPE html>
、<html>
和 <head>
,还有 <body>
以及它们对应的结束标记
删除后的代码如下
<h1>欢迎!</h1> <div>这个消息来自 Home 控制器下的 Index 的视图文件 index.cshtml </div> <table> @foreach (var employee in Model.Employees) { <tr> <td><a href="/Home/Detail/@employee.ID">@employee.ID</a></td> <td>@employee.Name</td> </tr> } </table>
当然了,我们还要引入布局视图和给 ViewBag
赋值一个 title
属性,这可以使用 @{}
C# 语句块来完成
@model HelloWorld.Controllers.HomePageViewModel @{ ViewBag.Title = "Home 控制器下的 Index 方法"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h1>欢迎!</h1> <div>这个消息来自 Home 控制器下的 Index 的视图文件 index.cshtml </div> <table> @foreach (var employee in Model.Employees) { <tr> <td><a href="/Home/Detail/@employee.ID">@employee.ID</a></td> <td>@employee.Name</td> </tr> } </table>
保存所有的代码,然后刷新浏览器,显示如下
每刷新一次时间就会变一次,是不是很有成就感?