专栏首页me的随笔ASP.NET Core MVC 视图

ASP.NET Core MVC 视图

ASP.NET Core MVC中视图的知识和ASP.NET MVC有很多相似之处,学习难度较低。以下内容主要体现了编程中模块化的思想,模块化才应是我们关注的重点。

Layout

布局用于提供各个页面所需的公共部分,如:菜单、页头、页尾等。在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

View Import & View Start

View Import

可以在_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: 后注入覆盖先注入的同名属性

View Start

_ViewStart.cshtml文件中的代码会在所有完整视图(full view,not layout,not partial view)文件被渲染之前执行。

默认情况下,ViewImports.cshtmlViewStart.cshtml文件直接位于Views文件夹下:

  • 相比其它位置的其它位置ViewImports.cshtmlViewStart.cshtml,直接位于Views文件夹中的ViewImports.cshtmlViewStart.cshtml文件会优先执行
  • 后执行的ViewImports.cshtml文件中的内容有可能会覆盖先执行ViewImports.cshtml文件中的内容
  • ViewImports.cshtmlViewStart.cshtml文件的作用域是当前目录及子目录

Tag Helper

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文件中后台代码与前端的搭配更和谐,利于提升代码可读性
  • 语法智能感知

Tag Helper 作用域

  • @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

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框架中,会从以下路径中加载局部视图文件,优先级从上而下依次降低:

  1. /Areas/<Area-Name>/Views/<Controller-Name>
  2. /Areas/<Area-Name>/Views/Shared
  3. /Views/Shared
  4. /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");
}

相比于PartialAsyncRenderParatialAsync有着更好的性能。

View Component

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

抄录一段微软官网上对于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 Invokemethod 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中的视图部分做了简要概述,相比于文中的各种概念,我们应该把注意力放到模块化设计上。模块化、抽象思维是程序员应该掌握的两种能力。他们可以让我们写出高内聚、低耦合的代码。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C#异步编程

    上面这段代码中,Main方法中的代码是按照自上而下的顺序执行的。网络状况不佳时,Start()方法是比较耗时(注意,这里在Start方法中调用了异步方法GetS...

    雪飞鸿
  • Python import 与 __all__

    使用from <module> import *导入模块时,若显式定义了__all__,则只导入__all__中的name,否则会导入除以下划线开头的所有nam...

    雪飞鸿
  • T-SQL基础(三)之子查询与表表达式

    在嵌套查询中,最外面查询结果集返回给调用方,称为外部查询。嵌套在外部查询内的查询称为子查询,子查询的结果集供外部查询使用。

    雪飞鸿
  • Mysql性能调优(二)

      从上篇文章开始,我们开始给大家陆续介绍mysql的优化部分。上篇文章首先给大家介绍了在Linux中安装和配置mysql的相关内容,接着给大家介绍了索引的相关...

    stefan666
  • ASP.NET MVC4 View 指定视图

    这个控制器操作没有指定视图的名称。当不指定视图名称时,操作方法返回的 ViewResult 对象将按照约定来确定视图,它会在目录 /View/Controlle...

  • SQL操作六

    爱撒谎的男孩
  • Laravel5.5 视图 – 创建视图和数据传递示例

    视图包含应用的 HTML 代码,并将应用的控制器逻辑和表现逻辑进行分离。视图文件存放在 resources/views 目录中。下面是一个简单的视图示例:

    砸漏
  • 关系数据库之视图

    The secret of change is to focus all of your energy, not on fighting the old but...

    小闫同学啊
  • 为什么SwiftUI的视图使用结构体?

    如果您曾经为UIKit或AppKit(Apple的iOS和macOS原始用户界面框架)编程,您会知道它们使用类而非结构体来构造视图。SwiftUI并非如此:我们...

    韦弦zhy
  • UIView中frame属性的内部实现

    UIView中用于表征视图在父视图中显示出来的位置和尺寸的属性是frame。 同时系统还提供另外两个属性center和bounds。其中center属性值描述视...

    欧阳大哥2013

扫码关注云+社区

领取腾讯云代金券