ASP.NET Core MVC中视图的知识和ASP.NET MVC有很多相似之处,学习难度较低。以下内容主要体现了编程中模块化的思想,模块化才应是我们关注的重点。
布局用于提供各个页面所需的公共部分,如:菜单、页头、页尾等。在ASP.NET Core中默认的布局文件是位于/Views/Shared文件夹下的_Layout.cshtml
文件:
我们通常在_Layout.cshtml
中引入公共资源,如:
<link href="~/css/reset.css" rel="stylesheet" />
<link href="~/css/index.css" rel="stylesheet" />
<script src="~/js/common/net/ajaxHandler.js"></script>
<environment names="Development">
<script src="~/js/lib/vue/vue.js"></script>
</environment>
<environment names="Production">
<script src="~/js/lib/vue/vue.min.js"></script>
</environment>
可以在Razor视图(即,cshtml文件)中使用Layout
属性来指定使用哪个布局文件:
@{
Layout="_Layout";
}
ASP.NET Core MVC搜索布局文件的方式与局部视图一样,下文中会详细说明。默认情况下,在布局文件中必须调用RenderBody
方法。还可以使用RenderSection方法来引入section
。
可以在_ViewImport.cshtm
文件中添加命名空间或者Tag Helper以供其它视图中使用,如:
@using Microsoft.AspNetCore.Identity
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
在_ViewImport.cshtm
文件可以使用以下指令:
@addTagHelper
@removeTagHelper
@tagHelperPrefix
@using
@model
@inherits
@inject
_ViewImport.cshtm
文件不支持Razor文件的其它特性,如:function、section等。对于多个_ViewImports.cshtml
的情况,指令运行结果遵循如下规则:
@addTagHelper
, @removeTagHelper
: 按照先后顺序执行
@tagHelperPrefix
: 后执行的结果覆盖先执行的结果
@model
: 后执行的结果覆盖先执行的结果
@inherits
: 后执行的结果覆盖先执行的结果
@using
: 引入所指定的所有命名空间,但忽略重复引用
@inject
: 后注入覆盖先注入的同名属性
_ViewStart.cshtml
文件中的代码会在所有完整视图(full view,not layout,not partial view)文件被渲染之前执行。
默认情况下,ViewImports.cshtml
和ViewStart.cshtml
文件直接位于Views文件夹下:
ViewImports.cshtml
和ViewStart.cshtml
,直接位于Views文件夹中的ViewImports.cshtml
和ViewStart.cshtml
文件会优先执行
ViewImports.cshtml
文件中的内容有可能会覆盖先执行ViewImports.cshtml
文件中的内容
ViewImports.cshtml
和ViewStart.cshtml
文件的作用域是当前目录及子目录
Tag Helper可以让服务器端代码参与到在Razor文件中创建和渲染HTML元素的工作中。
自定义Tag Helper:
public class XfhTagHelper : TagHelper
{
public string Content { set; get; }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "a";
output.Attributes.Add("href", "https://www.google.com");
output.Content.SetContent(Content);
}
}
使用Tag Helper:
@addTagHelper *,Web
<xfh content="haha">customer tag helper</xfh>
Tag Helper与HTML Helper有些相似,二者不同之处可参考:Tag Helpers compared to HTML Helpers
Tag Helper具有以下优点:
@addTagHelper
的第一个参数表示要加载哪些Tag Helper,使用"*"表示加载所有的Tag Helper;第二个参数表示从哪个程序集中加载Tag Helper。示例如下:
@* 需指明TagHelper的完全限定名 *@
@addTagHelper Web.TagHelpers.XfhTagHelper,Web
@removeTagHelper
也有两个参数,含义同@addTagHelper
@addTagHelper *,Web
@tagHelperPrefix th:
@* 不会被当作Tag Helper处理 *@
<xfh content="haha">customer tag helper</xfh>
<th:xfh content="tagHelperPrefix"></th:xfh>
Partial view,局部视图是一个Razor文件,它通常嵌套在另一个Razor文件中。局部视图主要用于拆分大的Razor文件及代码复用。但请注意:
局部视图名通常以下划线_
开头,下划线主要用于易于辨识局部视图文件。注意一点,在渲染局部视图时,不会执行_ViewStart.cshtml
文件中的代码。其余与普通视图一样。
⚠️局部视图中定义的
section
只对当前局部视图可见
引用局部视图文件而不带扩展名cshtml
时,在MVC框架中,会从以下路径中加载局部视图文件,优先级从上而下依次降低:
/Areas/<Area-Name>/Views/<Controller-Name>
/Areas/<Area-Name>/Views/Shared
/Views/Shared
/Pages/Shared
当引用局部文件带上扩展名时,局部视图文件必须和引用方位于相同目录下。
可使用以下方式引入局部视图:
<partial name="partial.cshtml" model="Model"/>
@* 局部视图文件后缀可以省略,如: *@
<partial name="partial" />
@* 也可以使用局部视图文件全名,如: *@
<partial name="~/Views/Shared/_PartialName.cshtml" />
@await Html.PartialAsync("_PartialName")
也可以使用 RenderPartialAsync方法来渲染局部视图,该方法直接将渲染结果写入到response中,而不是返回 IHtmlContent,所以只能在Razor代码块中调用该方法:
@{
await Html.RenderPartialAsync("_PartialName");
}
相比于PartialAsync
,RenderParatialAsync
有着更好的性能。
View component,视图组件和局部视图类似,但它更强大。一个视图组件包含两部分:
ViewComponent
类和一个视图。
视图组件不使用模型绑定,视图组件中所用的数据有调用者提供。视图组件有以下特点:
创建视图组件类:
ViewComponent
或使用ViewComponentAttribute
特性
ViewComponent
结尾(非强制)
public class FirstViewComponent : ViewComponent
{
// 方法名InvokeAsync是基于约定的,同步方法名为Invoke
public async Task<IViewComponentResult> InvokeAsync(string descript)
{
return View<string>(descript);
}
}
⚠️ 视图组件类中可以使用依赖注入。需注意:视图组件不会参与到Controller的生命周期中,所以filter对它无效。
创建视图文件:
视图组件默认视图名为:Default
,简单定义视图内容如下:
<label>
@Model
</label>
在运行时按照以下顺序搜索视图文件:
? 推荐使用Default作为视图组件的视图文件名,且视图文件存放路径为:Views/Shared/Components/{View Component Name}/{View Name}
可以使用如下两种方式来调用视图组件:
@addTagHelper *,Web
<div class="text-center">
@await Component.InvokeAsync("First", new { descript = "invoking view component" })
<br />
@* Tag Helper方式调用ViewComponent,需以vc:作为前缀 *@
<vc:first descript="tag helper">
</vc:first>
</div>
⚠️ 注意,使用Tag Helper形式调用视图组件时,组件名和组件的方法参数使用 kebab case方式,即,组件PriorityList
有参数maxPriority
,则调用方式如下:
<vc:priority-list max-priority="2">
</vc:priority-list>
除此之外,还可以在Controller中调用视图组件:
public IActionResult InvokeVC()
{
// 注意,视图组件名称大小写敏感
return ViewComponent("First", new { Descript = "controller"});
}
抄录一段微软官网上对于View component methods的总结,人太懒,就不翻译了?,留意加粗部分:
A view component defines its logic in an InvokeAsync
method that returns a Task<IViewComponentResult>
or in a synchronous Invoke
method that returns an IViewComponentResult
. Parameters come directly from invocation of the view component, not from model binding. A view component never directly handles a request. Typically, a view component initializes a model and passes it to a view by calling the View
method. In summary, view component methods:
InvokeAsync
method that returns a Task<IViewComponentResult>
or a synchronous Invoke
method that returns an IViewComponentResult
.
ViewComponent
View
method.
本文主要对ASP.NET Core中的视图部分做了简要概述,相比于文中的各种概念,我们应该把注意力放到模块化设计上。模块化、抽象思维是程序员应该掌握的两种能力。他们可以让我们写出高内聚、低耦合的代码。