_Layout模板
常规的页面一般由头部导航、左侧菜单、中间主体内容主成,而其中唯一变动的基本就只有中间主体内容了,而Layout模板就是用来做这样一件事,编写好模板,需要变动的地方则使用@RenderBody()方法
_ViewStart
我们尝试在_Layout模板的footer标签中增加一点内容,运行程序,发现也会跟着改动,明明在Index文件中未作任何操作
这是因为有_ViewStart的存在,发现里面默认有这样一行代码
@{
Layout = "_Layout";
}
如果在Index中头部未声明使用任何模板则会使用ViewStart定义的默认模板,默认一般是不定义,如果赋值为null或其它默认,则优先使用页面中定义的
页面加载顺序
_ViewStart.cshtml-->_Index.cshtml-->_Layout.cshtml
- 首先_ViewStart在所有View加载之前加载,设置了默认的模板页
- 接着由Controller指定的页面查找Index.cshtml加载,并读取该页面的Layout设置(在头部@{}中设置,如未设置则使用默认模板)
- 最后根据Index页面的Layout设置的模板页查找对应的模板页加载
我们尝试将ViewStart的Layout设置为_Layout1,运行程序,可以看到报错了
View的查找规则:先查找Controller对应的文件夹,若未找到,则到View/Shard和Pages/Shard文件夹查找,若最终还是未找到,则抛出异常
TagHelper
TagHelper与HtmlHelper对比
以下是在视图中使用TagHelper和HtmlHelper对比
@model HelloCore.Models.Book
@{
Layout = null;
}
@*HtmlHelper*@
@Html.EditorFor(m=>m.Name)
@Html.LabelFor(m=>m.Name)
<br />
@*TagHelper*@
<label asp-for=Name></label>
<input asp-for=Name />
通过浏览器F12看看这俩到底有啥区别
emm..目前看起来生成后的代码是没有多大区别,个人感觉主要区别还是在写法上,TagHelper相对HtmlHelper更为接近原生写法
比如,现在给它们都加一个样式,看看二者的写法
自定义TagHelper
创建一个类,名称建议以TagHelper结尾,并继承自TagHelper
重写ProcessAsync方法
public class LabelTagHelper : TagHelper
{
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
//校验label是否设置了show-type
if (output.Attributes.TryGetAttribute("show-type",out TagHelperAttribute tagHelperAttribute))
{
//校验设置的show-type是否为bookCode
if (tagHelperAttribute.Value.ToString().Equals("bookCode"))
{
//设置该标签的class为codeColor样式
output.Attributes.SetAttribute("class", "codeColor");
//获取标签的Contne内容
string content = output.Content.IsModified ? output.Content.GetContent() : (await output.GetChildContentAsync()).GetContent(); ;
//设置Content
output.Content.SetContent($"MVP{content}");
}
}
}
}
效果如下:
之所以会“乱码”,应该是编码问题,转一下就OK了
TagHelper注册
在_ViewImports中添加一行
@addTagHelper *,HelloCore
表示添加该程序集下所有TagHelper
TagHelper的作用范围
目前上面这种方式只能作用于label标签,如果p标签也要用,可以在类上加上特性注解
[HtmlTargetElement("p")]
public class LabelTagHelper : TagHelper{
}
但这样一来,label标签上就不起作用了
改造一下:
[HtmlTargetElement("p", Attributes = "show-type", ParentTag = "div")]
[HtmlTargetElement("label", Attributes = "show-type", ParentTag = "div")]
public class LabelTagHelper : TagHelper{
}
如果HtmlTargetElement设置多个,则是or的关系,也就是只要满足一个就会生效,通过Attributes和ParentTag属性会极大的缩小要作用的对象范围,ParentTag表示父标签
如果个别标签想要屏蔽TagHelper,则可以在标签尖括号后加上叹号
<!label show-type="bookCode" asp-for=Name class=codeColor></!label>
自定义标签
在页面中添加一个标签
<BookCode>1001</BookCode>
新增一个BookCodeTagHelper
public class BookCodeTagHelper : TagHelper
{
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.SetAttribute("class", "codeColor");
string content = output.Content.IsModified ? output.Content.GetContent() : (await output.GetChildContentAsync()).GetContent(); ;
output.Content.SetContent($"MVP{content}");
}
}
看看最后生成出来的HTML
注意:TagHelper会将大驼峰的命名方式转换成小写并以“-”分割
比如BookCodeTagHelper--->book-code
强大的VS还会根据我们所写的TagHelper给予提示和纠错
TagHelper与页面之间的数据传递
假设现在我们编号的前缀不再固定为“MVP”,我们可以这么做
修改TagHelper
修改页面
<book-code prefix="@Model.Prefix"></book-code>
还可以直接在标签中的prefix属性上传入整个@Model,然后在TagHelper中取出前缀属性拼接上去,效果是一样的
取消标签输出
自定义标签代码
[HtmlTargetElement("div", Attributes = "suppress-type")]
public class SuppressTagHelper : TagHelper
{
public string SuppressType { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (SuppressType.Equals("Suppress"))
{
output.SuppressOutput();
}
}
}
index代码
<div suppress-type="Suppress" >1002</div>
运行程序,可以看到页面中并未显示这个div,F12查看也并没有这个标签
TagBuilder
TagBuilder可以辅助生成标签
[HtmlTargetElement("div", Attributes = "simple-type")]
public class SimpleTagHelper : TagHelper
{
public string SimpleType { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (SimpleType.Equals("1"))
{
output.Content.SetHtmlContent("<p>傲慢与偏见</p>");
}
else if (SimpleType.Equals("2")) {
var p = new TagBuilder("p");
p.InnerHtml.Append("傲慢与偏见");
p.AddCssClass("codeColor");
output.Content.SetHtmlContent(p);
}
}
}
<div simple-type="1"></div>
<div simple-type="2"></div>