重用相同HTML代码。
ASP.NET MVC默认使用_ViewStart.cshtml指定默认的Layout页面:
Layout = "~/Views/Shared/_Layout.cshtml";
该_Layout.cshtml位于 ~/Views/Shared文件夹下,其中有一行:
@RenderBody()
ASP.NET MVC在运行/页面呈现时就会将其替换为内容页(比如Index.cshtml)的内容。
可以把@RenderBody()想象成一个“占位符”。
注意:
演示:对比_ViewStart中有无(被注释)Layout
两个页面共用一个Layout,但是他们除了@RenderBody()的那一部分不一样,还有其他一些小地方(section)也不一样。
但是一个Layout只能有一个@RenderBody()占位。
这就需要使用section:在RenderBody以外重用页面片段。
在Layout中声明
<h3>说明</h3> <p>@RenderSection("description")</p>
在内容页中指定section内容:
@section description{ <p>Register的说明</p> }
注意:
@if (IsSectionDefined("xxx")) { @RenderSection("xxx") }
@RenderSection("scripts", required: false)
内容页的Model数据,Layout可以使用:(演示)
public class LayoutModel { public string Name { get; set; } //…… public class Student : LayoutModel { public int Id { get; set; }然后在Layout中声明model
@model _17bang.Models.LayoutModel
因为ASP.NET MVC对Layout和内容页是分开编译的(利用报错演示,更详细的代码待学习.NET core RazorPages时查看)
此外,可以有多个嵌套的_Layout页面。比如:所有的页面共用header和footer,但是一部分页面是三列,一部分页面是两列,怎么办?
注意section也要一样的传递。
Layout和section还是有局限的。
网站中存在大量“布局无关”(位置随意)的、可重用的Html片段,比如:
这时候我们就需要使用其他可重用组件:
它分为两个部分:
PartialView的创建和普通View(.cshtml)类似
因为partial view只是一个“部分页面”,Partial View可以声明@model,但不应该有_Layout
同样的,partial view也没有Controller和Action
我们把“调用partial view的页面”称之为父页面。在父页面中使用@Html.Partial(),传入参数:
指定其路径,同return View(viewName))(复习)。
代码如下所示:
@*_LogOnStatus.cshtml在~/Views/User/下,注意.cshtml后缀不能省略*@ @Html.Partial("~/Views/User/_LogOnStatus.cshtml")
@*_LogOnStatus.cshtml和当前页面在同一个文件夹,*@ @*或者_LogOnStatus.cshtml在Shared文件夹下*@ @Html.Partial("_LogOnStatus") @*_LogOnStatus.cshtml在当前Action对应文件夹的子文件夹Yz下*@ @*或者_LogOnStatus.cshtml在Shared/Yz文件夹下*@ @Html.Partial("Yz/_LogOnStatus")
在实际开发中,PartialView的内容也需要“动态”呈现。
可以将一个ViewDataDictionary对象作为参数传递给PartialView:
@Html.Partial("_Partial", new ViewDataDictionary { { "id", 8 }, { "name", "阿泰" } })
F12演示:ViewDataDictionary的定义
这样在PartialView中,可以直接使用ViewData或者ViewBag:
<a href="/User/@ViewData["id"]">@ViewBag.name</a>
也可以传递强类型的Model:
@Html.Partial("_Partial", Model.Major)
这时候就可以/需要(以便智能提示)在PartialView上声明@model
@model _17bang.Models.Student
然后像普通view中使用model一样:
<a href="/User/@Model.Id">@Model.Name</a>
需要注意的是:如果传递给PartialView的model(比如Model.Major)为null值,或者根本就没有声明传递,ASP.NET MVC会把当前父页面的Model传递过去,于是出现这样的报错信息:
The model item passed into the dictionary is of type
'_17bang.Models.Student', but this dictionary requires a model item of
type '_17bang.Models.Major'.
@Html.Partial("_Partial", Model.Major) @*Model.Major=null*@ @Html.Partial("_Partial", null) @Html.Partial("_Partial")
按@Html.Partial()的方式调用PartilView,Model完全依赖于父页面。
如果想摆脱这种依赖,就要使用@Html.Action(),比如:
@Html.Action("_Reminder", "Register", new { id = 32 })
其中:
public PartialViewResult _Reminder(int id) //惯例:片段Html的Action和View都前缀下划线 { return PartialView(); }
注意 routeValue(id)的传值。
PartialView()的参数和View()的参数几乎一致。
通过PartialView() 返回的是一个部分页面(PartialViewResult),它和普通ViewResult最大的区别是:不受_ViewStart.cshtml内容控制(通常是自动引入_Layout)
Action中就可以写需要的后台逻辑,这就是ChildAction和Partial的最大区别!
在Action上可以添加 [ChildActionOnly],使其只能被其他View调用,不能独立响应HTTP请求。
换言之,如果没有[ChildActionOnly],该Action就可以被直接调用。
(演示:浏览器输入ChildAction的url访问……)
断点演示:
---------- 以下内容在 Model绑定 之后再讲 --------------
主要适用于form表单提交/子Model重用。
假设我们注册页面的“邀请人”部分会被重用:
namespace ViewModel.Register { public class IndexModel { public InviterModel Inviter { get; set; }
public class InviterModel { public string UserName { get; set; } public string Code { get; set; } }
@model ViewModel.Register.InviterModel <div> <label>邀请人:</label> @Html.TextBoxFor(m => m.UserName) </div> <div> <label>邀请码:</label> @Html.TextBoxFor(m => m.Code) </div>
那么,在Register.cshtml页面应该如何调用呢?
使用PartialView和ChildAction生成的页面看上去都没有问题,但在POST的时候(断点演示):
@想一想@:为什么?
如果想在父Action中就能直接取到子Model的值
首先,把对应的.cshtml文件(如:Inviter.cshtml)放在:
然后,在父页面中调用:
@Html.EditorFor(m => m.Inviter, "_Inviter")
断点演示:子model被成功绑定。
因为Editor生成的form表单不一样:
<input id="Inviter_UserName" name="Inviter.UserName" type="text" value="">注意它的name,不是UserName,而是Inviter.UserName
参数templateName可以省略,这时候MVC默认会在EditorTemplates下寻找和model同名的.cshtml文件做template,比如InviterModel,注意Model后缀
但如果template没有找到,并不会报错,只是没有template的样式等……(演示)
且无论如何,EditorTemplate只能放在EditorTemplates文件夹下。
#常见面试题:Partial()/Action()/Editor的区别?#
多快好省!前端后端,线上线下,名师精讲
更多了解 加: