作者: Jürgen Gutsch https://twitter.com/sharpcms/
翻译: 杨晓东 (Savorboard) https://www.cnblogs.com/savorboard
现在, 已经有很多种方式来扩展 Razor 视图了, 我们循循渐进, 先从最简单的开始.
如果你之前熟悉 MVC5(以及之前的 MVC) 中的视图的话, 有一部分你应该已经很熟悉了. 在新的 ASP.NET Core 中, 那些你熟悉的方式有一部分仍然能用, 只是 Core 版本针对视图又添加了一些东西. 这篇文章, 我们就来一起看看吧.
#1: 数据视图 (Typed Views)
这是一个不具有动态内容的最基本的一个视图, 就是你定义一个 ViewModel , 然后 ViewModel 具有一些默认值, 在视图上直接呈现而已. 定死的 ViewModel, 好像不是很常见, 以至于你使用 Visual Studio 新建一个默认的 web 应用程序的话, 都看不到它. 它就看起来像一个 *.cshtml 结尾的 HTML 文件, 但是, cshtml 文件却是服务端可以解析的一种文件, 所以你可以在里面使用一些 Razor 语法, 比如 HtmlHelpers,UrlHelpers 等. 同样, 你可以使用 ViewBag 或者 ViewData 来从 Controller 的 Action 传输数据到 View 里面, 来让它具有动态的内容. 但是 ViewBag 和 ViewData 都是弱类型的, 所以没有智能提示, 用起来略不爽.
要在你的视图中使用强类型数据对象, 你需要定义一个 Model 来在视图中使用.
- @model ExtendViews.ViewModels.AboutModel
- usage: --->
- @Model.FullName
这种方式是不是很常见的? 下一种方式是一个更好的方式来布局我们的视图:
#2: 布局 (Layouts):
相当于 ASP.NET 的 WebForms 的母版页, 不过它是定义 Razor 视图的基本布局的一种方式. 它就是_Layout.cshtml, 位于 Views\Shared 文件夹里 . 通常情况下这个文件通常包含 HTML 的 header,body 和公用的一些东西. 你可以多建几个互相进行组合, 来完成整个站点的布局. 其他页面引用布局视图页的时候, 是这样子写的 (注意不需要扩展名):
- @{
- Layout = "_Layout";
- }
此调用需要在您的视图的第一行中. 但你不需要在每一个视图中定义布局, 如果你使用 Visual Studio 新建一个 ASP.NET Core 项目, Views 文件夹有一个_ViewStart.cshtml, 在运行的时候它会自动的导入到每个视图中去.
在_Layout.cshtml 有一个方法法叫 RenderBody(), 它就是用来渲染详细的视图页到模板布局视图中:
@RenderBody()
在此方法的位置, 详情视图就会被渲染到这里.
#3: 区域 (Sections)
有时候子视图中想在主视图中显示一部分 HTML 代码, 比如 JavaScript 代码或者是 CSS, 这个时候就可以使用 Sections, 通常情况下在页面的结尾部分.
在主视图中 (_Layout.cshtml) 定义一个 Javascripts Section:
@RenderSection("scripts", required: false)
有一个 required 参数来声明这个 Section 是否必须的. 然后你就可以在子视图中这样使用:
- @section scripts
- {
- $(function() {
- // some more JS code here;
- });
- </script>
- }
如果你使用嵌套的布局, 你可能需要嵌套这个区域. 意思就是你在 Section 里面嵌套调用 RenderSection():
- @section scripts
- {
- @RenderSection("scripts", required: false)
- }
- #4: 分部视图 ( PartialViews)
你可以提取 HTML 页面中重用的部分, 把它放到一个新的 Razor 视图中, 这个视图没有自己的 Action, 这种视图就叫做分部视图. 分部视图通常也在 Views\Shard \ 文件夹.
分部视图同样也可以是一个数据视图, 它可以从父视图中获取数据 (但不是必须的):
- @model IEnumerable<UserModel>
- @if (Model.Any())
- {
- @foreach (var user in Model)
- {
- @user.FullName</li>
- }
- </ul>
- }
这个分部视图需要从父视图中获取用户列表的数据
@{ await HTML.RenderPartialAsync("Users", Model.Users);}
如果你的分部视图没有定义用户模型, 你就不需要传第二个参数.
#5: 视图组件 (ViewComponents)
这个 ASP.NET Core 特有的.
译者注: 类似于以前的用户控件
有时候你需要做一些分部视图的事情, 但是又包含一些业务逻辑在里面. 在过去, 你可以使用 ChildAction 渲染结果到一个视图中, 但是, 在 ASP.NET Core 中, 有一种新的方式来做这件事情, 它就是 ViewComponents(我已经写了一篇关于 ViewComponents 的博文). 它类似于在 MVC 中的一种迷你的 MVC, 也就是说他们可以有自己的 Controller, 和单个的 action 以及 view.ViewComponents 是完全独立于你的当前视图的, 但是可以通过你当前的视图传输数据.
想这样调用它, 来渲染一个 ViewComponents:
@Component.Invoke("Top10Articles");
可以看我的博客来学习怎么创建自己的 ViewComponent.
#6: HTML 助手 (HtmlHelpers)
在 HTMLHelper 类中, 你可以创建你自己的扩展方法来扩展 Razor 语法:
- public static class HtmlHelperExtensions
- {
- public static HtmlString MyOwnHtmlHelper(this HtmlHelper helper, string message)
- {
- return new HtmlString($"{message}");
- }
- }
在你的视图中, 创建一个可重用的部分是非常有用的, 它比分部视图多包含了一些业务逻辑. 比 HTMLHelpers 扩展更好的是新的 TagHelpers, 但是在扩展你视图的时候, HTMLHelpers 仍然有它自己的一些适用的地方.
#7: 标签助手 (TagHelper)
这是 ASP.NET Core 非常好的一个新特性.
一个扩展你视图的小助手, 它看起来像一个原生的 HTML 标签一样. 在 ASP.NET Core MVC 中你应该使用 TagHelpers 来替换 HtmlHelpers, 因为它们更加的简洁和容易使用. 另一个巨大的好处就是依赖注入, 在 HtmlHelpers 中是使用不了的, 因为 HtmlHelpers 扩展的都是静态内容. 但 TagHelpers 是一个公共类, 我们可以很容易的在它的构造函数中注入服务.
下面是一个很简单的小示例, 来展示怎么样定义一个 TagHelper:
- [TargetElement("hi")]
- public class HelloTagHelper : TagHelper
- {
- public override void Process(TagHelperContext context, TagHelperOutput output)
- {
- output.TagName = "p";
- output.Attributes.Add("id", context.UniqueId);
- output.PreContent.SetContent("Hello");
- output.PostContent.SetContent(string.Format(", time is now: {0}",
- DateTime.Now.ToString("HH:mm")));
- }
- }
这里定义了一个叫做 hi 的标签, 它以 HTML 标记来呈现, p 标签的内容是当前时间.
使用:
<hi>John Smith</hi>
结果:
<p>Hello John Smith, time is now: 18:55</p>
ASP.NET Core MVC 已经默认提供了很多 TagHelpers 来替换以前的 HtmlHelpers. 例如 ActionLink 已经被新的 TagHelper 所替换:
@HTML.ActionLink("About me", "About", "Home")
新的 TagHelper 像这样来创建一个 link:
<a asp-controller="Home" asp-action="About">About me</a>
以上两种方式来创建一个 a 标签的结果:
<a href="/Home/About">About me</a>
可以看到, TagHelpers 看起来更像原生的 HTML, 他们在视图中更加的直观, 更高的可读性, 并且更容易使用.
#8: 依赖注入 (Dependency Injection)
这也是 ASP.NET Core 的新特性.
在扩展你的视图的时候, 可以使用依赖注入了, 这是一个非常大改进. 是的, 你可以在你的视图中使用 DI 了.
在 Stack Overflow 和 reddit 有人这样问?
这真的有意义吗? 这不是会搞乱我的视图吗? 这不是与 MVC 模式背离吗?
我认为, 不是这样的. 的确, 在真正需要的地方你才使用, 并且, 你使用的时候需要非常小心. 有这样一个有效的场景: 你创建一个表单来编辑用户的资料信息 (User Profile), 用户可以添加他的公司位置, 地址, 国家城市等等, 我不愿意从 Action 到 View 中传输公司位置 , 地址和国家城市. 我只愿意通过用户资料本身 (User Profile), 我只想在 Action 中处理用户资料 (User Profile). 这时候可以注入服务来给我查询数据, 这就是为什么这种情况下它是非常有用的. 它可以让我们的 Action 和 ViewModel 保持非常的干净.
在 Startup.cs 中的 ConfigureServices 来注册你具体的服务, 然后你就可以在视图中这样来使用, 只需要一行代码:
@inject DiViews.Services.ICountryService CountryService;
现在你可以在你的视图中使用 ContryService 来填充国家下拉列表.
我在这篇博客中写了很多关于依赖注入的博文.
#9: 函数 (Functions)
在一个 ASP.NET MVC 项目中, 我从来没有真正的使用过函数这个功能. 我只在一个 Umbraco 的 CMS 系统中用过一次. 不管怎么说, 这也是扩展你视图的另一种小技巧. 也许你有很复杂视图方面的业务逻辑, 在这种情况下, 你可以在你的视图中写 C# 方法:
- @functions
- {
- public string ReverseString(string input)
- {
- return String.Join("", input.Reverse());
- }
- }
- #10: 配置全局视图 (Global view configuration)
最后一点, 你可以在_ViewImports.cshtml 文件中, 来配置你其他视图中使用的一些比较公用的 using 引用, 依赖注入等.
总结
不管是以前的 MVC 还是新的 Core MVC, 都有很多方法来扩展视图, 虽然扩展这些视图的方式有些类似, 但是每一种都有它最适合的地方, 所以我们在使用这些特性来解决我们的问题的时候, 我们应该多加思考, 找到最合适的方式.
译者注: 本文翻译并非逐字翻译, 由于水平有限, 难免出现一些错误和翻译不准确的地方, 希望读者能够指出并堪正, 不胜感激.
来源: http://www.bubuko.com/infodetail-3320998.html