Razor布局页面 _ViewStart.cshtml
知识点0:
标识符 @
Razor支持HTML和C#代码混编,意味着可以在代码块中插入HTML、在HTML中插入Razor语句都是可以的。
(0)在代码块中插入HTML、在HTML中插入Razor语句
@{
int num1 =10;
int num2 =5;
int sum = num1 + num2;
string color ="Red";
<font color="@color">@sum</font>
}
输出@符号:@@
输出Email地址:Razor模板会自动识别出Email地址,所以不需要我们进行任何的转换。而在代码块中,只需要使用 @:Tom@gmail.com 即可。@:表示后面的内容为文本。
输出HTML代码(包含标签):直接输出,string html = “文本”; @html
输 出HTML内容(不包含标签):有两种方法,第一种:IHtmlString html=new HtmlString(“文本”); @html; 第二种:string html = “文本”; @Html.Raw(html);
(1)直接@后面跟变量(当遇到 HTML标签 、空格、换行符等特殊符号时 便认为@之后到特殊符号前为变量名,特殊符号后的内容原样输出)
<p>my name is @ViewBag.name</p>
my job is @ViewBag.job
以上代码输出了 ViewBag.name 和ViewBag.job 的值
(2)@后面跟大括号(代码段声明,代码段中代码全部当做C#代码 ,但是HTML标签会原样输出 ,输出变量同样适用@)
@{
List<Employee> employees = new List<Employee>();
for (int i = ; i < ; i++)
{
Employee employee = new Employee();
employee.Name = "李二狗" + i;
employee.Age = + i;
employee.Job = (Career)(i/);
employees.Add(employee);
}
}
<table>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>职业</td>
</tr>
@* 从这里开始声明C#代码段 *@
@foreach (Employee item in employees)
{
<tr>
@* 在C#代码段中 HTML标签会被原样输出(混编的好处) 输出变量需要在前面加上@ *@
<td>@item.Name</td>
<td>@item.Age</td>
<td>@item.Job.ToString()</td>
</tr>
}
</table>
知识点1:
MVC中执行任何一个视图之前都要先执行Views文件夹下的 _ViewStart.cshtml 视图的内容
注意点:想要上面的描述成立,则在action方法中必须以return View()来返回视图。
如果是以PowerView() 方法来返回视图的话,则不会执行_ViewStart.cshtml 中的内容
public class HomeController : Controller
{
public ActionResult Index()
{
//MVC中执行任何一个视图之前都要先执行Views文件夹下的_ViewStart.cshtml视图的内容
// ↓↓
return View(); //但是只有以return View()的形式返回视图,才会执行_ViewStart.cshtml视图中的内容
//return PartialView(); 如果如果是以PowerView() 方法来返回视图的话,则不会执行_ViewStart.cshtml 中的内容
}
}
}
知识点2:
_ViewStart.cshtml 视图文件的作用
_ViewStart.cshtml 文件的作用:一般是用于存放MVC网站中所有视图公用的js,css等文件。这样就不需要在每个视图中都拖一个js,css等文件进来了。
(1)引入静态文件
.net MVC提供一套静态文件打包工具
需要在/App_Start/BundleConfig.cs中先定义,例如
//在视图中引入Content/css相当于引入 bootstrap.css 和 site.css
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css"));
视图中使用
@Styles.Render("~/content/home")
//引入css
@Scripts.Render("~//bundles/jquery")
//引入js
项目相关结构如下:
_ViewStart.cshtml就是MVC中的布局页面/模板页面。
_ViewStart.cshtml 文件内容举例:
@{ Layout = "_Layout"; }
@*利用Razor视图开始(_ViewStart)批量配置布局
当有非常多视图都需要引入相同的布局时,在_ViewStart中编写的引用在其作用域下所有的视图都会被加上相应的代码,引用其规定的Razor布局
*@@*当相同文件夹内的文件要使用不同布局时,只能在内容页里使用Layout属性
当不同的文件夹内的如果要使用不同的布局时,可以在相应的文件夹下新建_ViewStart.cshtml文件
*@@*在视图中使用@{Layout}的引用>写在与视图同目录的视图开始中的引用>写在父目录的视图开始的引用
即如果某一页需要单独引用不同的视图布局,则可以使用优先级更高的方式覆盖优先级低的方式。
*@@{ Layout = "teacher/_Layout"; }
模板渲染过程
Views/_Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
<!--每个虚拟路径下面的物理文件是在MVC网址启动的时候就调用了Global.asax文件下的Application_Start()方法中的BundleConfig.RegisterBundles(BundleTable.Bundles)方法,这样就将每个虚拟路径映射好了具体的物理文件-->
<!--Styles.Render(""虚拟路径"") :输出此虚拟路径下包含的物理css文件-->
@Styles.Render("~/Content/css")
<!--Scripts.Render(""虚拟路径"") :输出此虚拟路径下包含的物理js文件-->
@Scripts.Render("~/bundles/jquery")
<!--RenderSection()也是一个占位符,它是一个带有标识的占位符。将来会被使用了此模板页的子页面带有指定标识的内容来替换-->
<!--它可以有多个。-->
<!--required: false表示在使用模板页中的子页面中不重写这个节点,如果是true则必须重写-->
@RenderSection("scripts", required: false)
<!--比如,这里我再自定义一个RenderSection()-->
@RenderSection("Mycss",required:true)
</head>
<body>
<div style="width:800px;margin:0px auto">
<div style="border:1px solid red; height:50px">顶部内容</div>
<div>
<div style="float:left; width:150px; height:500px; border:1px solid blue" >
<ul>
<li>菜单1</li>
<li>菜单2</li>
<li>菜单3</li>
</ul>
</div>
<div style="float: right; width: 640px; height: 500px; border: 1px solid blue">
<!--这个RenderBody()就是占位符,将来会被使用了模板页的子页面的内容给替换掉-->
<!--这个RenderBody()占位符,只能在布局也中出现一次-->
@RenderBody()
@RenderSection("bodyArea", required: false)
</div>
</div>
</div>
</body>
</html>
Views/Home/Index.cshtml
在看看我们继承这个模板页的子页面 (Home控制器下的Index视图,它使用了上面这个模板页)
@{
ViewBag.Title = "Index";
}
<!-- 子页面中所有没有使用@section地方都是对应Layout中@RenderBody()-->
<h2>Index</h2>
@section scripts{
<script type="text/javascript">
alert("你好");
</script>
}
@section Mycss{
<style type="text/css">
* {
color:red;
}
</style>
}
<!--对应Layout中@RenderSection("bodyArea", required: false) ,required: false不是必填-->
@section headArea{
required: false不是必填
}
渲染出来的HTML页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<!--每个虚拟路径下面的物理文件是在MVC网址启动的时候就调用了Global.asax文件下的Application_Start()方法中的BundleConfig.RegisterBundles(BundleTable.Bundles)方法,这样就将每个虚拟路径映射好了具体的物理文件-->
<!--Styles.Render(""虚拟路径"") :输出此虚拟路径下包含的物理css文件-->
<link href="/Content/site.css" rel="stylesheet"/>
<!--Scripts.Render(""虚拟路径"") :输出此虚拟路径下包含的物理js文件-->
<script src="/Scripts/jquery-1.8.2.js"></script>
<!--RenderSection()也是一个占位符,它是一个带有标识的占位符。将来会被使用了此模板页的子页面带有指定标识的内容来替换-->
<!--它可以有多个。-->
<!--required: false表示在使用模板页中的子页面中不重写这个节点,如果是true则必须重写-->
<script type="text/javascript">
alert("你好");
</script>
<!--比如,这里我再自定义一个RenderSection()-->
<style type="text/css">
* {
color:red;
}
</style>
</head>
<body>
<div style="width:800px;margin:0px auto">
<div style="border:1px solid red; height:50px">顶部内容</div>
<div>
<div style="float:left; width:150px; height:500px; border:1px solid blue" >
<ul>
<li>菜单1</li>
<li>菜单2</li>
<li>菜单3</li>
</ul>
</div>
<div style="float: right; width: 640px; height: 500px; border: 1px solid blue">
<!--这个RenderBody()就是占位符,将来会被使用了模板页的子页面的内容给替换掉-->
<!--这个RenderBody()占位符,只能在布局也中出现一次-->
<h2>Index</h2>
</div>
</div>
</div>
</body>
</html>
即:将模板_Layout.cshtml中的占位符替换成HOME/index.cshtml中对应的模块所替换
子页面不使用布局页面
所有的视图页面都使用了布局页面,因为每次请求都会执行【_ViewStart.cshtml页面】,【_ViewStart.cshtml页面】对页面的Layout属性赋值了。
很多不使用布局页面的都会清空Layout。
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>TransData</title>
</head>
<body>
</body>
</html>
那么这个页面中就不会使用到各级模板_Layout.cshtml中所提供的页面布局,只用它自己的页面(常可用于系统中的登录页面)。
用户访问流程图:
原理:先去执行Views文件夹下【_ViewStart.cshtml】页面,然后同级目录文件夹(上图中的home文件夹)下执行【_ViewStart.cshtml】页面(如果同级目录文件夹下有【_ViewStart.cshtml】页面),最后执行请求视图(上图Index.cshtml页面)。
那么当存在多个ViewStart.cshtml文件的时候执行顺序是什么呢?
答:
1>首先是执行Views文件夹下的ViewStart.cshtml视图文件的内容。当我们访问的是Home文件夹下的的视图的时候,Home文件夹下的ViewStart.cshtml文件才会被执行。
也就是先执行了Views文件夹下的ViewStart.cshtml视图文件内容,后才执行Home文件夹下的ViewStart.cshtml视图内容
2>当我们访问的是Test文件下的视图的时候,就仅仅是执行Views文件夹下的ViewStart.cshtml视图内容(因为Test文件夹下不存在ViewStart.cshtml视图文件)
举例
MVC中任何视图页面最终都会被创建成一个页面类对象,【_ViewStart.cshtml】页面也不例外,它是被创建【继承StartPage抽象类的一个页面类对象】,所以它可以使用StartPage抽象类中的属性和方法。
StartPage抽象类图
布局页面传值可以使用PageData
c#中前后端进行数据交互的常见三种方式:
- ViewData 字典类型,存放键值对an
- ViewBag 非键值对数据,而是dynamic动态数据
- TempData 默认保存Session中,控制器每次从Session中获取TempData,然后清除Session。
eg:
控制器中:
ViewBag.a=“a”;
ViewData[“b”]=“b”;
TempData[“c”]=“c”;
视图中:
@ViewBag.a
@ViewData[“b”]
@TempData[“c”]
运行后显示:
abcPS:其中ViewBag和ViewData是可以混用的例如控制器中ViewBag.a=“a”,视图中@ViewData[“a”],运行后也可以输出a,反之亦然(两者是一个继承关系,所以可以混用)
①Views文件夹下的_ViewStart.cshtml
②Views /Teacher文件夹下的_ViewStart.cshtml
③Views/Teacher文件夹下的Index.cshtml(注:Index.cshtml没有使用_ViewStart.cshtml布局页面)
④结果:执行顺序 Views 下ViewStart.cshtml =>Teacher下ViewStart.cshtml => Teacher下Index.cshtml