ASP.NET Core MVC中视图的知识和ASP.NET MVC有不少类似之处,学习难度较低。如下内容主要体现了编程中模块化的思想,模块化才应是咱们关注的重点。css
布局用于提供各个页面所需的公共部分,如:菜单、页头、页尾等。在ASP.NET Core中默认的布局文件是位于/Views/Shared文件夹下的_Layout.cshtml
文件:html
咱们一般在_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
属性来指定使用哪一个布局文件:vue
@{ Layout="_Layout"; }
ASP.NET Core MVC搜索布局文件的方式与局部视图同样,下文中会详细说明。默认状况下,在布局文件中必须调用RenderBody
方法。还可使用RenderSection方法来引入section
。程序员
能够在_ViewImport.cshtm
文件中添加命名空间或者Tag Helper以供其它视图中使用,如:ajax
@using Microsoft.AspNetCore.Identity
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
在_ViewImport.cshtm
文件可使用如下指令:编程
@addTagHelper
api
@removeTagHelper
服务器
@tagHelperPrefix
mvc
@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具备如下优势:
类HTML语法
这一点是我喜欢Tag Helper的缘由,使用Tag Helper可使cshtml文件中后台代码与前端的搭配更和谐,利于提高代码可读性
语法智能感知
@addTagHelper
@addTagHelper
的第一个参数表示要加载哪些Tag Helper,使用"*"表示加载全部的Tag Helper;第二个参数表示从哪一个程序集中加载Tag Helper。示例以下:
@* 需指明TagHelper的彻底限定名 *@
@addTagHelper Web.TagHelpers.XfhTagHelper,Web
@removeTagHelper
@removeTagHelper
也有两个参数,含义同@addTagHelper
@tagHelperPrefix
给Tag Helper加上前缀标识,示例以下:
@addTagHelper *,Web @tagHelperPrefix th: @* 不会被看成Tag Helper处理 *@ <xfh content="haha">customer tag helper</xfh> <th:xfh content="tagHelperPrefix"></th:xfh>
Partial view,局部视图是一个Razor文件,它一般嵌套在另外一个Razor文件中。局部视图主要用于拆分大的Razor文件及代码复用。但请注意:
局部视图不该用来维护公共布局中的内容,考虑使用_Layout.cshtml来维护公共布局
Partial views shouldn't be used to maintain common layout elements.
尽可能不要在局部视图中使用复杂的渲染逻辑,或者须要执行一些代码片断才能获取到视图元素。这种状况考虑使用view component来替代局部视图。
Don't use a partial view where complex rendering logic or code execution is required to render the markup.If you need to execute code, use a view component instead of a partial view.
局部视图名一般如下划线_
开头,下划线主要用于易于辨识局部视图文件。注意一点,在渲染局部视图时,不会执行_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" />
HTML Helper
@await Html.PartialAsync("_PartialName")
也可使用 RenderPartialAsync方法来渲染局部视图,该方法直接将渲染结果写入到response中,而不是返回 IHtmlContent,因此只能在Razor代码块中调用该方法:
@{ await Html.RenderPartialAsync("_PartialName"); }
相比于PartialAsync
,RenderParatialAsync
有着更好的性能。
View component,视图组件和局部视图相似,但它更强大。一个视图组件包含两部分:
ViewComponent
类和一个视图。
视图组件不使用模型绑定,视图组件中所用的数据有调用者提供。视图组件有如下特色:
渲染数据块而非整个响应
关注点分离、易于测试
能够有参数和业务逻辑
MVC自己就提倡关注点分离,因此,视图组件中应尽量只包含与渲染视图相关的逻辑
一般在层中调用
建立视图组件类:
视图组件继承自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>
在运行时按照如下顺序搜索视图文件:
/Views/{Controller Name}/Components/{View Component Name}/{View Name}
/Views/Shared/Components/{View Component Name}/{View Name}
/Pages/Shared/Components/{View Component Name}/{View Name}
🆗 推荐使用Default做为视图组件的视图文件名,且视图文件存放路径为:Views/Shared/Components/{View Component Name}/{View Name}
可使用以下两种方式来调用视图组件:
Component.InvokeAsync
Tag Helper
@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:
Define an InvokeAsync
method that returns a Task<IViewComponentResult>
or a synchronous Invoke
method that returns an IViewComponentResult
.
Typically initializes a model and passes it to a view by calling the ViewComponent
View
method.
Parameters come from the calling method, not HTTP. There's no model binding.
Are not reachable directly as an HTTP endpoint. They're invoked from your code (usually in a view). A view component never handles a request.
Are overloaded on the signature rather than any details from the current HTTP request.
本文主要对ASP.NET Core中的视图部分作了简要概述,相比于文中的各类概念,咱们应该把注意力放到模块化设计上。模块化、抽象思惟是程序员应该掌握的两种能力。他们可让咱们写出高内聚、低耦合的代码。
View components in ASP.NET Core