ASP.NET Core 3.0 : 二十五. TagHelper

什么是taghelper?这是asp.net core 中新出现的一个名词,它的作用是使服务器端代码可以在razor 文件中参与创建和呈现html 元素。(asp.net core 系列目录)

一、概述

上面的解释有点拗口?那么换一个名词,htmlhelper大家都知道吧,在asp.net core中,taghelper类似htmlhelper,但可以说是青出于蓝而胜于蓝。那么taghelper的作用也就大概明白了吧。

首先通过一个例子看一下taghelper是怎么使用的,看看它和htmlhelper有什么区别。新建一个book类:

    public class book
    {
        [display(name = "编号")]
        public string code { get; set; }
[display(name = "名称")]
        public string name { get; set; }
    }

新建对应的controller和action:

    public class bookcontroller : controller
    {
        // get: /<controller>/
        public iactionresult index()
        {
            return view(new book() { code = "001", name = "asp" });
        }
    }

最后就是view了:

@model book
@{
    layout = null;
}
@html.labelfor(m => m.name)
@html.editorfor(m => m.name)
<br />
<label asp-for="name"></label>
<input asp-for="name" />

这里分别通过htmlhelper和taghelper两种方式实现了一个文本和输入框的显示。查看网页源代码,可以看到二者生成的html如下:

<label for="name">name</label>
<input class="text-box single-line" id="name" name="name" type="text" value="asp" />
<br/>
<label for="name">name</label>
<input type="text" id="name" name="name" value="asp" />

目前看起来二者差不多,从工作量上来看也是区别不大。现在功能实现了,需要做一些样式处理。简单举个例子,现在希望book的编号(code)对应的label的颜色设置为红色,定义了一个css如下:

<style type="text/css">
    .codecolor {
        color:red;
    }
</style>

然后准备把这个样式应用到label上,这时如果是htmlhelper就很有可能会被问:“class写在哪”,估计好多人都被问过。然后我们告诉他可以这样写:

@html.labelfor(m=>m.name,new {@class="codecolor"})

前端工程师添加后达到了想要的效果,但同时表示记不住这个写法,下次可能还会问。

如果是taghelper就方便了,告诉他可以像平时给html的标签添加class一样操作即可,也就是:

<label asp-for="name" class="codecolor"></label>

前端工程师表示这种写法“真是太友好了”。同样对于form及验证,比较一下两种写法的不同,htmlhelper版:

@using (html.beginform("index", "home", formmethod.post)){    
@html.labelfor(m => m.code)
    @html.editorfor(m => m.code)    @html.validationmessagefor(m => m.code)    <input type="submit" value="提交" />
}

taghelper版:

<form asp-action="index" asp-controller="home" method="post">
    <label asp-for="code"></label>
    <input asp-for="code" />
    <span asp-validation-for="code"></span>
    <input type="submit" value="提交" />
</form>

二、自定义taghelper

现在有这样的需求,用于显示book的编号的label不止要添加名为codecolor的css样式,还要给书的编号自动添加一个前缀,例如“bj”。

对于这样的需求,希望可以通过一个简单的标记,然后由taghelper自动实现。例如:

<label show-type="bookcode">1001</label>

自定义了一个属性“show-type”,用于标识这个label的显示类别,“1001”为假定的图书编号。通过这样的设置方式,将来如果需求有变化,需要对编号的显示做更多的修饰,只需修改对应的taghelper即可,而页面部分不需要做任何调整。

系统提供了方便的自定义taghelper的方式,就是继承系统提供的taghelper类,并重写它的process/processasync方法,例如下面的例子:

    public class labeltaghelper : taghelper
    {
        public override async task processasync(taghelpercontext context, taghelperoutput output)
        {
            if (output.attributes.trygetattribute("show-type", out taghelperattribute showtypeattribute))
            {
                if (showtypeattribute.value.tostring().equals("bookcode"))
                {
                    output.attributes.setattribute("class", "codecolor");

                    string content = output.content.ismodified ? output.content.getcontent() : (await output.getchildcontentasync()).getcontent(); ;
                    output.content.setcontent("bj" + content);
                }
            }
        }
    }

首先判断label是否被设置了show-type="bookcode",然后获取当前label的content内容,将其添加前缀“bj”后作为此label的content的新内容。注意一下content的获取方式,如果它没有被修改,凭感觉直接通过output.content.getcontent()获取到的内容是空的。

访问index页面,可以看到改标签已被处理,如下图:

备注:a.关于获取show-type的值,还可以有其他方式,下文会讲到。

b.从规范化命名的角度,建议将自定义的taghelper其命名为xxxaghelper这样的格式。

三、taghelper的注册

taghelper自定义之后需要将其注册一下,否则它是不会生效的。打开_viewimports.cshtml,默认为:

@using taghelperdemo
@using taghelperdemo.models
@addtaghelper *, microsoft.aspnetcore.mvc.taghelpers

在最下面添加一条

@addtaghelper *, taghelperdemo

最后添加的这一句话是什么意思呢?也就是将程序集taghelperdemo(即第二个参数)中的所有taghelper(第一个参数为“*”,即所有)全部启用。假如还定义了一个passwordtaghelper,但只想只添加labeltaghelper,可以这样写:

@addtaghelper taghelperdemo.taghelpers. labeltaghelper, taghelperdemo

如果想添加所有自定义的taghelper,但要去除labeltaghelper呢?

那么可以先添加所有,再去除这个labeltaghelper。

@addtaghelper *, taghelperdemo
@removetaghelper taghelperdemo.taghelpers. labeltaghelper, taghelperdemo

四、taghelper的作用范围

在项目中,可能不止使用label标签来显示book的code,还有可能会是p、span等类型的标签,现在的需求是,无论是上述哪一种标签,都要实现添加css和前缀的功能。

现在将index.cshtml中新增一个p标签如下:

<p show-type="bookcode">1002</p>

访问这个页面发现1002未被处理。这是因为我们定义的taghelper名为labeltaghelper,在默认的情况下只会处理label标签。当然也可以做特殊设置,例如下面代码的写法:

    [htmltargetelement("p")]
    public class labeltaghelper : taghelper
    {
      //代码省略
    }

通过“[htmltargetelement("p")]”指定本taghelper只能被使用于p标签。再次访问此页面,发现p标签被处理了,而label未被处理。这说明这样的显式指定的优先级要高于默认的名称匹配。除了设置指定标签,还可以有一些其他的辅助设置:

[htmltargetelement("p", attributes = "show-type", parenttag = "div")]
public class labeltaghelper : taghelper

可以这样写,会匹配p标签,要求该标签拥有show-type属性,并且父标签为div。这几个条件是“and”的关系。如果还想匹配label标签,可以添加对label的设置,例如下面代码这样:

[htmltargetelement("p", attributes = "show-type", parenttag = "div")]
[htmltargetelement("label", attributes = "show-type", parenttag = "div")]
public class labeltaghelper : taghelper

这两个htmltargetelement的关系是“or”。通过这样的设置,可以极大的缩小目标标签的范围。

但是这样设置之后,这个taghelper的名字再叫labeltaghelper就不合适了,例如可以改为bookcodetaghelper,最终代码如下:

[htmltargetelement("p", attributes = "show-type", parenttag = "div")]
[htmltargetelement("label", attributes = "show-type", parenttag = "div")]
public class bookcodetaghelper : taghelper
{
    public override async task processasync(taghelpercontext context, taghelperoutput output)
    {
        if (output.attributes.trygetattribute("show-type", out taghelperattribute showtypeattribute))
        {
            if (showtypeattribute.value.tostring().equals("bookcode"))
            {
                output.attributes.setattribute("class", "codecolor");

                string content = output.content.ismodified ? output.content.getcontent() :
                                    (await output.getchildcontentasync()).getcontent(); ;
                output.content.setcontent("bj" + content);
            }
        }
    }
}

如果想使个别html标签屏蔽taghelper的作用,可以使用“!”。例如下面两个标签:

<!label show-type="bookcode">1001</label>

五、自定义标签

上一节最终形成了一个名为bookcodetaghelper的taghelper,我们知道labeltaghelper是可以按名称默认匹配label标签的,那么是否可以自定义一个bookcode标签呢?在index.cshtml中添加这样的代码:

<bookcode>1003</bookcode>

 

由于自定义bookcode标签的目的就是专门显示book的code,所以也不必添加show-type属性了。然后修改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("bj" + content);
    }
}

 

去掉了两个htmltargetelement设置并取消了对show-type的判断,访问index页面查看新建的bookcode标签是否会被处理,结果是没有被处理。这是为什么呢?

这是由于taghelper会将采用pascal 大小写格式的类和属性名将转换为各自相应的短横线格式。即“bookcode”对应“book-code”,获取标签的属性值,同样遵循这样的规则。所以将标签改为如下写法即可:

<book-code>1003</book-code>

再次运行测试,发现这个新标签被成功处理。查看网页源代码,被处理后的html代码是这样的:

<book-code class="codecolor">tj1003</book-code>

如果想将其改变为label,可以在bookcodetaghelper中通过指定tagname实现:

public class bookcodetaghelper : taghelper
{
    public book book { get; set; }
    public override async task processasync(taghelpercontext context, taghelperoutput output)
    {
        output.tagname = "label";
        output.attributes.setattribute("class", "codecolor");

        string content = output.content.ismodified ? output.content.getcontent() :
                            (await output.getchildcontentasync()).getcontent(); ;
        output.content.setcontent(book.prefix + content);
    }
}

六、taghelper与页面之间的数据传递

假如现在的新需求是图书编码的前缀不再固定为“bj”了,需要在标签中定义,例如这样:

<book-code prefix="sh">1003</book-code>

需要获取prefix的值,在上面的例子中采用的是trygetattribute方法,其实还有简单的方式,修改bookcodetaghelper,代码如下:

   public class bookcodetaghelper : taghelper
    {
        public string prefix { get; set; }
        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(prefix + content);
        }
    }

标签中的prefix的值会自动赋值给bookcodetaghelper.prefix,是不是更方便了。那么如果是model中的值呢?假如book类有一个属性“public string prefix { get; set; } ”,这和传入一个字符串没什么区别,那么可以这样写:

<book-code prefix="@model.prefix">1003</book-code>

这种传值方式不止是支持字符串,将model整体传入也是支持的,将标签修改如下:

<book-code book="@model">1003</book-code>

修改bookcodetaghelper代码:

    public class bookcodetaghelper : taghelper
    {
        public book book { get; set; }
        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(book.prefix + content);
        }
    }

七、取消标签输出

前面的几个例子都是对满足条件的标签的修改,taghelper也可以取消对应标签的输出,例如存在这样一个标签:

<div simple-type="simple1"></div>

如果不想让它出现在生成的html中,可以这样处理:

[htmltargetelement("div",attributes = "simple-type")]
public class simple1taghelpers : taghelper
{
    public string simpletype { get; set; }
    public override void process(taghelpercontext context, taghelperoutput output)
    {
        if (simpletype.equals("simple1"))  //可以是其他一些判断规则
        {
            output.suppressoutput();
        }
    }
}

八、tagbuilder

在taghelper中,可以用tagbuilder来辅助生成标签,例如存在如下两个div:

<div simple-type="simple2"></div>
<div simple-type="simple3"></div>

想在div中添加html元素可以这样写:

[htmltargetelement("div",attributes = "simple-type")]
public class simple1taghelpers : taghelper
{
    public string simpletype { get; set; }
    public override void process(taghelpercontext context, taghelperoutput output)
    {
        if (simpletype.equals("simple2"))
        {
            output.content.sethtmlcontent("<p>simple2</p>");
        }
        else if (simpletype.equals("simple3"))
        {
            var p = new tagbuilder("p");
            p.innerhtml.append("simple3");
            output.content.sethtmlcontent(p);
        }
    }
}

通过tagbuilder生成了一个新的p标签,并将它插入到div中。

 

本文链接:https://2i3i.com/aspnetcore_25.html ,转载请注明来源地址。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇