【ASP.NET Core】标记帮助器——替换元素名称

asp,net,core,标记,帮助,替换,元素,名称 · 浏览次数 : 1350

小编点评

**特征**: * **别名**:`group-name` * **类型**:标签 * **属性**: * `id`:用于标识元素的 ID * `name`:用于给元素命名 * `value`:用于指定元素的选项值 * `checked`:用于指定元素是否被选中 * `label`:用于显示元素的文本标签 **示例**: ```html
``` **结果**: ```html
``` **总结**: * `group-name` 属性用于分组选项。 * `label` 属性用于显示选项的文本。 * `checked` 属性用于指定选项是否被选中。

正文

标记帮助器不仅可以给目标元素(标记)插入(或修改)属性,插入自定义的HTML内容,在某些需求中还可以替换原来标记的名称。

比如我们在使用 Blazor 时很熟悉的 Component 标记帮助器。在 Razor 文档中你将使用 <Component> 元素来设置要呈现的组件。而在实际处理时,会去掉 <Component> 元素,并呈现组件的HTML内容。

下面咱们举两个例子。

第一个比较简单,自定义的元素是 <textBox>,生成的元素是 <input type=text />。

[HtmlTargetElement("textBox", TagStructure = TagStructure.WithoutEndTag)]
public class TextInputTagHelper : TagHelper
{
    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        // 将标记名称改为 input
        output.TagName = "input";
        // 设置 type 属性
        output.Attributes.SetAttribute("type", "text");
    }
}

这个不难理解,首先我们用的是候,在 Razor 文档使用的是元素是 <textbox>,而最后呈现出来的 HTML 是 <input> 元素。咱们就把它弄得像个控件那样用,是不是有点以前 ASP.NET 的味儿了?以前是有个前缀 asp:TextBox。

TagStructure.WithoutEndTag 的意思是指定这个标记没有结束标签,就像 <input > 或 <input />。

Razor 文档中要用 @addTagHelper 指令导入一下。

@addTagHelper *, TestApp

TestApp 是我这个程序集的名称,它导入此程序集下所有标记帮助器。

用起来也方便。

<div>
    <TextBox />
</div>

运行之后,生成这样的 HTML。

<input type="text">

咱们确实可以让它更像传统 ASP.NET。

@addTagHelper *, TestApp
@tagHelperPrefix "asp:"

<div>
    <asp:textBox />
</div>

@tagHelperPrefix 就是为标记添加一个前缀,这里指定的是“asp:”,所以用的时候就真的捡到“童年回忆”了。想当年,ASP.NET 就是这么用的。

 

下面再举一例,咱们做 RadioButton(单选按钮)。选项之间互斥,同一个分组中你只能选择一项。在 HTML 中是 <input type=radio >,它没有“分组”属性,而是通过 name 属性来分组。name 相同的就是同一组,互斥。

注意的是,<input type=radio> 只显示个圈圈让你可以选中,可不包含选项文本。一般我们会给它配个 <label> 元素。然后,<label> 元素的 for 属性指向 <input> 的 id 属性。这样二者就关联了,点击<label>也能选中单选按钮。

所以,咱们实现的帮助器要生成一个<div>,里面包含<input>和<label>两个元素。

[HtmlTargetElement("radioButton", TagStructure = TagStructure.WithoutEndTag)]
public class RadioInputTagHelper : TagHelper {

    // 分组名称
    [HtmlAttributeName("group-name")]
    public string? Group { get; set; } = "radio";

    // id 值
    public string? Id { get; set; } = string.Empty;

    // 标签文本
    public string? Label { get; set; }

    // 默认是否选中
    public bool IsChecked { get; set; } = false;

    // 选项代表的值
    public string? Value { get; set; } = string.Empty;

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        // 修改标记名称
        output.TagName = null;

        StringBuilder builder = new();
        string html = $"""
        <div>
            <input type="radio" id="{Id}" name="{Group}" value="{Value}" {(IsChecked ? "checked" : "")} />
            <label for="{Id}">{Label}</label>
        </div>
        """;

        // 设置HTML内容
        output.Content.SetHtmlContent(html);
    }
}

默认情况下,在 Razor 文档中使用标记帮助器时,属性与.NET类属性相同。比如这个类中的 Label 属性,在Razor代码中也是Label属性。

<radioButton Label="老司机" ……>

如果你希望 HTML 属性与 .NET 属性不同,可以加上 [HtmlAttributeName] 特性,配分一个别名。

[HtmlAttributeName("group-name")]

咱们这个例子中,就为 Group 属性分配一个别名—— group-name。

<label> 元素只是呈现在HTML中的文本,让用户看,很多时候程序处理的往往不是这个,而是让标签对应一个值,即 Value 属性。Value 属性指定的值才是给程序用的。

我们来用一下这个单选按钮。

<div>
    <radioButton group-name="abc" id="itme1" value="1" label="山药" is-checked="true" />
    <radioButton group-name="abc" id="item2" value="2" label="鸭梨" />
    <radioButton group-name="abc" id="item3" value="3" label="龙眼" />
    <hr />
    <radioButton group-name="good" id="item5" value="5" label="大卡车" />
    <radioButton group-name="good" id="item6" value="6" label="皮卡" is-checked="true" />
    <radioButton group-name="good" id="item4" value="4" label="独轮车" />
</div>

同一 group-name 下的选项是互斥关系,而不同组之间是互不影响的。

运行后,生成以下 HTML:

 <div>
    <input type="radio" id="itme1" name="abc" value="1" checked />
    <label for="itme1">山药</label>
</div>
<div>
    <input type="radio" id="item2" name="abc" value="2"  />
    <label for="item2">鸭梨</label>
</div>
<div>
    <input type="radio" id="item3" name="abc" value="3"  />
    <label for="item3">龙眼</label>
</div>
<hr />
<div>
    <input type="radio" id="item5" name="good" value="5"  />
    <label for="item5">大卡车</label>
</div>
<div>
    <input type="radio" id="item6" name="good" value="6" checked />
    <label for="item6">皮卡</label>
</div>
<div>
    <input type="radio" id="item4" name="good" value="4"  />
    <label for="item4">独轮车</label>
</div>
</div>

结果如下图所示。

 

接下来看第三个例子。咱们来画一个圆,标记帮助器定义一个 <circle> 元素,我们直接设置相关属性就行。比如画布宽度、画布高度、圆的圆心、半径、线的粗细。然后会生成 <canvas> 元素和相关的 js 脚本代码。

[HtmlTargetElement("Circle")]
public class CircleTagHelper : TagHelper
{
    // 圆的半径
    public int Radius { get; set; }

    // 线宽度
    public int LineWidth { get; set; }

    // 圆心-X
    public int CenterX { get; set; }

    // 圆心-Y
    public int CenterY { get; set; }

    // 画布宽度
    public int Width { get; set; } = 300;

    // 画布高度 
    public int Height { get; set; } = 300;

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        // 无标记名称
        output.TagName = null;
        // 生成的内容
        string s = $"""
            <canvas id="cv" width="{Width}" height="{Height}"></canvas>
            <script>
                var canvas = document.getElementById('cv');
                var ctx = canvas.getContext('2d');
                ctx.lineWidth = {LineWidth};
                ctx.strokeStyle = 'blue';
                ctx.beginPath();
                ctx.arc({CenterX}, {CenterY}, {Radius}, 0, 2 * Math.PI);
                ctx.stroke();
            </script>
            """;
        output.Content.SetHtmlContent(s);
    }
}

TagName 设置为 null 表示咱们这个帮助器不生产标签,而是用输出字符串 s 中那段代码。即这段代码直接呈现在 HTML 文档中,外部不用其他元素包装。

来,咱们在 Razor 文档中试试看。

<Circle center-x="115" center-y="90"
        width="900"
        height="900"
        line-width="4"
        radius="70" />

绘制的圆如下图所示。

 

生成的 HTML 如下:

<canvas id="cv" width="900" height="900"></canvas>

<script>
    var canvas = document.getElementById('cv');
    var ctx = canvas.getContext('2d');
    ctx.lineWidth = 4;
    ctx.strokeStyle = 'blue';
    ctx.beginPath();
    ctx.arc(115, 90, 70, 0, 2 * Math.PI);
    ctx.stroke();
</script>

用这个方法,咱们可以封装出许多图形绘制的标记,用的时候只要赋值一下属性即可,很省事的哟。

 

与【ASP.NET Core】标记帮助器——替换元素名称相似的内容:

【ASP.NET Core】标记帮助器——替换元素名称

标记帮助器不仅可以给目标元素(标记)插入(或修改)属性,插入自定义的HTML内容,在某些需求中还可以替换原来标记的名称。 比如我们在使用 Blazor 时很熟悉的 Component 标记帮助器。在 Razor 文档中你将使用 元素来设置要呈现的组件。而在实际处理时,会去掉

【ASP.NET Core】标记帮助器——抽象层

标记帮助器,即 Tag Helpers。这个嘛,就直接翻译了,叫“标记帮助器”,虽然不好听,但只能这样了。当然你翻译为“标记增强器”也行。 所谓标记帮助器,就是针对 HTML 标签(不管是标准的还是自己命名的)进行扩展的做法。它是以 Razor 为基础的,服务于开发人员的。在服务器端用 C# 代码来

【ASP.NET Core】标记帮助器——元素筛选

前一篇中老周从标记帮助的底层介绍关键性的接口,如 ITagHelper ,它是一个标志,用于识别哪些类属于 Tag Helper。 标记帮助器毕竟是针对 HTML 标记的,所以得筛选。说白了就是我写的这个帮助器在哪些 HTML 标记上起作用。这就需要拿出一个特性类。 [AttributeUsage(

ASP.NET Core 8 预览版 4的重大更新

最新版本的 .NET 8 预览版 4 对 ASP.NET Core 进行了重大改进。值得注意的增强功能包括 Blazor 的流式呈现和表单处理、在最小 API 中扩展对表单绑定的支持、用于提高性能的NativeAOT 编译、使用标识 API 终结点增强的身份验证和授权,以及添加用于应用程序监视的指标

[翻译].NET 8 的原生AOT及高性能Web开发中的应用[附性能测试结果]

随着 .NET 8 的发布,微软迈出了重要一步,为 ASP.NET Core 引入了原生的 Ahead-of-Time (AOT) 编译。这一进步不仅提高了应用程序的性能,还简化了开发过程,标志着 .NET 生态系统进入了新的时代。

NET9 AspnetCore将整合OpenAPI的文档生成功能而无需三方库

OpenAPI 规范是用于描述 HTTP API 的标准。该标准允许开发人员定义 API 的形状,这些 API 可以插入到客户端生成器、服务器生成器、测试工具、文档等中。尽管该标准具有普遍性和普遍性,但 ASP.NET Core 在框架内默认不提供对 OpenAPI 的支持。 当前 ASP.NET

ASP.NET Core中创建中间件的几种方式

前言 今天我们一起来盘点一下在ASP.NET Core应用程序中添加和创建中间件常见的四种方式。 中间件介绍 ASP.NET Core中间件(Middleware)是用于处理HTTP请求和响应的组件,它们被安排在请求处理管道中,并按顺序执行。中间件的设计是为了使其在请求处理管道中能够以灵活和可扩展的

推荐十个优秀的ASP.NET Core第三方中间件,你用过几个?

ASP.NET Core 作为一个强大的、跨平台的、高性能的开源框架,为开发者提供了丰富的功能和灵活的扩展性。其中,中间件(Middleware)是 ASP.NET Core 架构中的核心组件之一,它负责处理 HTTP 请求和响应的管道,允许开发者在请求和响应之间插入自定义逻辑。随着 ASP.NET

Asp-Net-Core开发笔记:使用原生的接口限流功能

前言 之前介绍过使用 AspNetCoreRateLimit 组件来实现接口限流 从 .Net7 开始,AspNetCore 开始内置限流组件,当时我们的项目还在 .Net6 所以只能用第三方的 现在都升级到 .Net8 了,当然是得来试试这个原生组件 体验后:配置使用都比较简单,不过功能也没有 A

ASP.NET Core如何禁用模型验证(或者从模型状态中移除某些属性)?

这是一篇4年前的文章:【经验分享】在ASP.NET Core中,如果禁用某个请求的模型验证? 事隔多年,又有网友问到这个问题。我就来重新整理一下,顺便扩展一下之前的解决办法。 这是一个来自网友【David】的提问。在 AppBoxCore 项目的新增用户页面,新增一个上传按钮: