4.2 Razor语法与页面辅助功能


文档摘要

4.2 Razor 语法与页面辅助功能 Razor 语法的核心是 @ 符号的四种用法:输出表达式、语句块、指令、标记过渡;页面辅助功能则解决"页面写多了怎么复用"——分区组织目录、分部视图复用片段、视图组件封装自带数据的模块。语法十分钟,组织力才是本节的重点。 上一节搭好了页面骨架,本节解决两个日常问题:Razor 混写规则到底有几条(比想象中少);页面数量上来之后,导航、卡片、侧栏这些东西放在哪。观察哨的判断始终是管线式的:每件辅助工具都对应管线上的一个执行时机。 @ 符号的四副面孔 四副面孔覆盖全部日常:指令声明页面属性、语句块写逻辑、表达式输出值、关键字写流程。转义只需记两条:输出 @ 本身写 @@;输出 HTML 原文(非编码)用 Html.Raw 且只用于可信内容——3.

4.2 Razor 语法与页面辅助功能

Razor 语法的核心是 @ 符号的四种用法:输出表达式、语句块、指令、标记过渡;页面辅助功能则解决"页面写多了怎么复用"——分区组织目录、分部视图复用片段、视图组件封装自带数据的模块。语法十分钟,组织力才是本节的重点。

上一节搭好了页面骨架,本节解决两个日常问题:Razor 混写规则到底有几条(比想象中少);页面数量上来之后,导航、卡片、侧栏这些东西放在哪。观察哨的判断始终是管线式的:每件辅助工具都对应管线上的一个执行时机。

@ 符号的四副面孔

@page <!-- 面孔一:指令,@ 开头 + 关键字,编译期处理 --> @model IndexModel <!-- 声明页面模型的类型 --> @{ var titles = new[] { "首页", "热销" }; <!-- 面孔二:语句块,执行不输出 --> var count = titles.Length; } <p>共 @count 个栏目</p> <!-- 面孔三:表达式,求值并输出(HTML 编码) --> <p>原始输出 @@符号</p> <!-- 连写两个 @ 输出一个 @ --> @if (count > 1) <!-- 面孔四:关键字过渡,C# 控制结构接管 --> { <text>多个栏目</text> <!-- text 标记:块内输出纯文本 --> }

四副面孔覆盖全部日常:指令声明页面属性、语句块写逻辑、表达式输出值、关键字写流程。转义只需记两条:输出 @ 本身写 @@;输出 HTML 原文(非编码)用 Html.Raw 且只用于可信内容——3.4 节说过,编码是防注入的第一道闸。

环境信息与页面状态

页面开发有两个高频小需求:判断当前环境(开发期才显示调试面板)、在 GET 与 POST 之间带一点状态。环境判断用环境标签助手,状态用页面模型属性与 TempData 的组合:

<environment include="Development"> <div class="debug-panel">仅开发环境可见的调试面板</div> </environment> <!-- 生产环境渲染后此块消失,不需要手写 if 判断环境变量 -->
public class EditModel : PageModel { [BindProperty] // 属性绑定:页面模型不必靠方法参数接值 public ProductInput Input { get; set; } = new(); [TempData] // 跨一次跳转存活:PRG 后仍能读到 public string? Message { get; set; } public IActionResult OnPost() { if (!ModelState.IsValid) return Page(); Message = $"已保存 {Input.Name}"; // 写入 TempData return RedirectToPage("Index"); // 跳转后 Index 页仍可读取显示 } }

BindProperty 让属性直接参与模型绑定(3.3 节的规则原样适用),页面通道里比方法参数更常见;TempData 属性把"跳转后还要显示一次"的场景写成一行。

页面组织三件套:分区、分部、视图组件

页面过了三十个,三件事必然发生:目录需要分组、同样的片段在多个页面重复、某个"自带数据的小模块"到处粘贴。三件套各对一症:

图 4.2-1 页面复用三件套的选型卡

图 4.2-1 页面复用三件套的选型卡

三件套的调用方式各一行:

<!-- 分部视图:数据由调用方准备好 --> <partial name="_ProductCard" model="item" /> <!-- 视图组件:一行唤起,内部自己取数渲染 --> <vc:hot-list count="5" /> <!-- 分区里的链接:分区名进路由 --> <a asp-area="Admin" asp-page="/Reports/Index">后台报表</a>

自定义一个 TagHelper:把重复标记收进一个标签

TagHelper 家族可以扩展。页面里到处出现的"金额展示框"(带币种符号与样式),可以收进一个自定义标签:

// 自定义 TagHelper:把金额格式化逻辑收进 money 标签 public class MoneyTagHelper : TagHelper { public decimal Value { get; set; } // 标签属性自动映射 public string? Currency { get; set; } // 可选属性 public override void Process(TagHelperContext ctx, TagHelperOutput output) { var symbol = Currency == "USD" ? "$" : "¥"; output.TagName = "span"; // 输出标签改为 span output.Attributes.SetAttribute("class", "money"); output.Content.SetContent($"{symbol}{Value:N2}"); // N2:千分位两位小数 } }
<!-- 页面里:一处声明,处处整洁 --> <money value="@item.Price" currency="CNY" /> <!-- 渲染结果:<span class="money">¥199.00</span> -->

案例复盘:某电商站商品页与列表页各自手写金额格式化,一处改千分位规则漏改三处,金额显示不一致引发客服工单。收进 MoneyTagHelper 后格式化规则单一来源,一次修改全站生效。变式:需要异步取数的标签(徽标上显示库存)改写异步版本;配置驱动的属性(币种符号表)从 IConfiguration 注入——2.3 节的机制在自定义组件里照常可用。

问题:分部视图与视图组件会不会拖慢渲染?

两者都是进程内渲染,开销远小于一次数据库往返。真正的性能陷阱是"循环里调视图组件查库"——每行卡片查一次库。判定方法:看组件的 SQL 次数(第 5 章的日志观察窗能看到),而不是猜。

⚠️ 常见坑:把 TagHelper 写成了 HTML Helper 的风格竞赛。两者能力重叠,项目里应统一主线(TagHelper 为主、Html.Helper 兜底),混用两套风格会让后来者难辨"这个写法是特性还是遗留"。

本节要点回顾

  • @ 四副面孔:指令、语句块、表达式输出、关键字过渡,编码输出是默认防线;
  • BindProperty 与 TempData 属性是页面通道的两个高频装备,分别接绑定与跨跳转状态;
  • 复用三件套:分区管目录隔离、分部管纯展示复用、视图组件管自带数据的模块;
  • 自定义 TagHelper 把重复标记与格式化规则收进单一来源,配置注入照常可用;
  • 性能判定靠观察(SQL 次数),组件本身不背锅,循环查库才是真凶。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U