当前位置: 代码网 > it编程>编程语言>Asp.net > ASP.NET Core中的Blazor组件介绍

ASP.NET Core中的Blazor组件介绍

2024年05月18日 Asp.net 我要评论
项目 blazor 中,使用.razor结尾的文件,称为组件;而 blazor 中的组件,正式名称是razor 组件;blazor 组件是 razor 过渡而来的,使用 razor 的基本语法特性,但

项目 blazor 中,使用 .razor 结尾的文件,称为组件;而 blazor 中的组件,正式名称是 razor 组件;

blazor 组件是 razor 过渡而来的,使用 razor 的基本语法特性,但是 balzor 不支持 razor 中的标记帮助程序。

关于组件

.razor 文件分为页面(带@page)和组件(不带@page,或者说页面组件和非页面组件。两者区别在于页面有路由,可以直接通过 uri 访问,一般放在 page 文件夹中;而组件,作为一个部件,必须嵌入其它组件中,在页面中显示,一般放到 shared 文件夹中,供多个页面共享、复用。
本文接下来所指的组件都是非页面组件。
.razor 文件中,开头有 @page 标记的,就是页面组件,没有的就是非页面组件。
当然两者并没有严格的区分。
组件命名时,应该带上 component 后缀。

组件类

每个 .razor 文件,在编译后会生成一个类,称为组件类。 生成的类的名称与文件名匹配。
因此,每个 .razor 文件,必须以大写字母开头,按照类名命名规范定义文件名称。

`.razor` ,以 `@code{}` 包含 c# 代码,这部分代码除了组件间可以使用,程序中也可以正常使用,因为属于类的一部分。

创建 test.razor 文件,文件内容如下:

@code{
    public string name { get; set; }
}

pargrom 中:

            pages.test test = new pages.test();
            test.name = "blazor";

简单来说,就是可以作为一个类来使用。@code{} 中定义的成员,就是类的成员。
成员正常使用 public 、private 等访问修饰符修饰。

静态资产

默认静态资源文件位置在项目的 wwwroot 目录,前端(.razor、.cshtml)等,默认寻址时,使用绝对路径 / 即可访问资源。
例如:

<img alt="company logo" src="/images/logo.png" />

这个路径是要放到前端才能,由前端访问时 asp.net core 框架自动处理,相当于前端访问 / ,后端访问 d:/test/blazor/wwwroot

路由与路由参数

页面组件使用 @page 设置此页面的访问地址,这里没有 controller 和 action 的分层和路由导航(相对地址),直接是一个绝对的访问地址,并且全局唯一。

index.razor 中,路由:

@page "/"

blazor 不支持像 controller 和 action 那样设置灵活的 url 可选参数(url query),例如:

        [httpget("test/{id}")]
        public string test([fromquery]int id)
        {
            return "123";
        }

blazor 如果想通过 url query 传递参数,可以使用 {name}

@page "/test"
@page "/test/{id}"

<h2>@id</h2>

@code{
    [parameter]
    public string id { get; set; } = "123";
}

因为 blazor 不支持可选参数,因此,如果只设置 @page "/test/{id}",那么每次访问都必须带有这个参数值。
需要使用 [parameter] 来修饰成员,才能捕获 @page "/test/{id}"
另外,理由参数是 string 类型,不能自动转为数值类型。不如会报错:

invalidoperationexception: unable to set property 'id' on object of type 'blazorapp1.pages.test'. the error was: unable to cast object of type 'system.string' to type 'system.int32'.

你可以接收后,显式转为数值类型。

组件参数

在 @code 代码块中,使用 [parameter] 修饰的公共属性,那么这个属性就会标识为组件指定参数。
注意官网文档中,这个小节的代码示例,实际是不允许这样写得的。
目前,有两个地方需要使用 [parameter] 特性,一个是前一小节的路由参数绑定,另一个是嵌入组件时使用。
示例:
test.razor 文件内容:

<h2>@title</h2>

@code{
    [parameter]
    public string title { get; set; } = "test";
}

别的组件嵌入 test.razor 这个组件时,就可以使用 title 传递参数进去:

<test title="111" />

请勿创建会写入其自己的组参数属性的组件

前面我们说到, [parameter] 特性的使用,这个特性时作为参数传递而使用的。
对于路由参数,其修饰的属性应该是 privite,对于其它组件传递参数,属性应该设置为 public
如果一个组件的 @code{} 成员不需要被外界作为参数使用,就应该设置为 private
因为 .razor 一般不会作为类来使用。、;而且不设置 [parameter] 的属性,别的组件也使用不了这个属性。

那么,文档说 “请勿创建会写入其自己的组参数属性的组件”,指定是 [parmeter] 休息的属性,是作为参数传递使用的,不要在组件中修改这个属性的值。

如果实在要操作的话,可以先拷贝这个值,使用别的变量操作,示例:

<h2>@title</h2>

@code{
    [parameter]
    public string title { get; set; } = "test";

    private string _title;
    protected override void oninitialized()
    {
        _title = title;
    }
}

这样,组件要操作的话,可以使用 _title ,保留 title
oninitalized() 是一个组件初始化的方法,也可以理解成构造函数,可以参考 https://docs.microsoft.com/zh-cn/aspnet/core/blazor/lifecycle?view=aspnetcore-3.1#component-initialization-methods

子内容

因为组件是可以嵌套的,可以要求另一个组件显示要求的内容。

  • 被多个组件使用,不同组件要呈现不一样的内容;
  • 要根据父组件的配置,显示子组件;
  • 组件 a 要求使用到的组件 b,显示其传递的内容;

简单来说,就是将页面内容作为复杂类型传递给另一个组件,要求这个组件显示出来。
那么,子内容指的是一个组件可以接收另一个组件的内容,使用 renderfragment 来接收内容。
示例如下:
test.razor 中,内容:

<div>@children</div>

@code{
    [parameter]
    public renderfragment children { get; set; }
}

另一个组件:

@page "/"

<test children=r />
@code{
    private renderfragment r =@<h1>测试子内容</h1>;
}

renderfragment 的使用,请自行查阅资料。

属性展开

属性展开是使用字典类型表示一个 html 标签的多个属性。

<input id="1"
       maxlength="@maxlength"
       placeholder="@placeholder"
       required="@required"
       size="@size" />

<input id="2"
       @attributes="inputattributes" />

@code {
    #region
    private string maxlength { get; set; } = "10";
    private string placeholder { get; set; } = "input placeholder text";
    private string required { get; set; } = "required";
    private string size { get; set; } = "50";
    #endregion

    // 使用字典键值对表示
    public dictionary<string, object> inputattributes { get; set; } = new dictionary<string, object>()
    {
            { "maxlength", "10" },
            { "placeholder", "input placeholder text" },
            { "required", "required" },
            { "size", "50" }
     };
}

任意参数

[paramter] 特性,只有一个属性,其定义如下:

        public bool captureunmatchedvalues { get; set; }

文档说明:[parameter] 上的 captureunmatchedvalues 属性允许参数匹配所有不匹配任何其他参数的特性。
其作用是通过字典接收在父组件中出现但是未在 @code{} 中定义的参数属性。
例如:
test.razor 中

@code{
    // 这个属性没有用,随便起个名字测试
    [parameter]
    public string a { get; set; }

    [parameter(captureunmatchedvalues = true)]
    public idictionary<string, object> additionalattributes { get; set; }
}

父组件中使用:

<test a="a"
      b="b"
      c="c" />

b、c 都是 test.razor 中没有出现过的,那么这些参数和参数值都会自动转为键值对存储到 additionalattributes 中。

测试示例:
test.razor 中的内容

<ul>
    @foreach (var item in additionalattributes)
    {
        <li>@item.key - @item.value</li>
    }
</ul>

@code{
    // 这个属性没有用,随便起个名字测试
    [parameter]
    public string ttt { get; set; }

    [parameter(captureunmatchedvalues = true)]
    public idictionary<string, object> additionalattributes { get; set; }
}

其它组件使用:

@page "/"

<test ttt="ces"
      id="useindividualparams"
      maxlength="10"
      placeholder="input placeholder text"
      required="required"
      size="50" />

捕获对组件的引用

组件引用提供了一种引用组件实例的方法,使用 @ref 可以实现引用对参数的引用。
创建一个 test.razor 文件,内容不限。
在一个组件中,引用该组件实例

@page "/"
<test @ref="_test" />
@code{
    private test _test;
}

在使用 test.razor 组件的同时,保留了引用,以便在 @code{} 中使用其成员。

在外部调用组件方法以更新状态

组件继承了 componentbase 类型,有个 invokeasync 方法可用于外界更新此 ui 的状态。

示例如下:
创建 myuiserver 类型,

    // 能够向所有正在打开的 index.razor 页面发送通知
    public static class myuiserver
    {
        // 向所有人发送通知
        public static async task tomessage(string message)
        {
            if (events != null)
            {
                await events.invoke(message);
            }
        }
        public static void addevent(func<string, task> func)
        {
            events += func;
        }
        public static void removeevent(func<string, task> func)
        {
            events -= func;
        }
        private static event func<string, task> events;
    }

在 index.razor 中

@page "/"
@using blazorapp1.data
@implements idisposable

<input @bind="_message" />
<button @onclick="btn">发送消息</button>
<ul>
    @foreach (var item in messagelist)
    {
        <li>@item</li>
    }
</ul>

@code {
    private string _message;
    private list<string> messagelist = new list<string>();
    // 进入页面时
    protected override void oninitialized()
    {
        myuiserver.addevent(uievent);
    }

    // 退出当前页面ui后移除该事件
    public void dispose()
    {
        myuiserver.removeevent(uievent);
    }

    protected async task uievent(string message)
    {
        // 组件自带的方法,用于外部调用更新状态
        await invokeasync(() =>
        {
            messagelist.add(message);
            statehaschanged();
        });
    }

    // 向所有正在访问 index.razor 页面发送消息
    private async task btn()
    {
        await myuiserver.tomessage(_message);
    }

}

打开多个窗口,访问页面 https://localhost:5001/,在其中一个窗口输入内容并且点击按钮,即可将消息内容推送到其它窗口。

下面是一个修改官网示例的示例:
创建一个类型 notifierservice

    public class notifierservice
    {
        public async task update(string key, int value)
        {
            if (notify != null)
            {
                await notify.invoke(key, value);
            }
        }

        public event func<string, int, task> notify;
    }

该类型的 notify 可以绑定多个事件;通过调用 update() 方法,可以触发各个事件。
在 startup 中注入服务 services.addsingleton<notifierservice>();
index.razor 中,内容为:

@page "/"
@using blazorapp1.data
@inject notifierservice notifier
@implements idisposable

<p>last update: @_lastnotification.key = @_lastnotification.value</p>

@code {
    private (string key, int value) _lastnotification;

    protected override void oninitialized()
    {
        notifier.notify += onnotify;
    }

    public async task onnotify(string key, int value)
    {
        // 组件自带的方法,用于外部调用更新状态
        await invokeasync(() =>
        {
            _lastnotification = (key, value);
            statehaschanged();
        });
    }

    // 退出当前页面ui后移除该事件
    public void dispose()
    {
        notifier.notify -= onnotify;
    }
}

test.razor 文件中:

@page "/test"
@using blazorapp1.data
@inject notifierservice notifier
key:
<input @bind="key" />
value:
<input @bind="value" />
<button @onclick="update">更新</button>

@code{
    private string key { get; set; }
    private int? value { get; set; }
    private async task update()
    {
        await notifier.update(key, value.value);
        key = string.empty;
        value = null;
    }
}

然后启动项目,一个页面打开 https://localhost:5001/ ,另一个页面打开 https://localhost:5001/test
在 test 页面输入 key 和 value,点击按钮,即可通知到所有正在打开 index.razor 的页面。

使用 @ 键控制是否保留元素和组件

在使用表格或了表等元素时,如果出现插入或删除、更新等情况,整个表格或列表,就会被重新渲染。这样会带来比较大的性能消耗。
一般使用绑定的元素,其更新是自动的,不需要人为控制。
在能保证每一项的某个元素列,都是唯一的时候,我们可以使用 @key 关键字来优化组件。
示例:

@page "/"
@using blazorapp1.data

key:
<input @bind="_key" />
value:
<input @bind="_value" />
<button @onclick="add">添加</button>
<button @onclick="remove">移除</button>
<ul>
    @foreach (var item in dic)
    {
        <li @key="item.key">@item.key - @item.value</li>
    }
</ul>

@code {
    private int? _key;
    private int _value;
    private list<mydata> dic { get; set; } = new list<mydata>();
    private void add()
    {
        if (_key == null)
            return;
        dic.add(new mydata
        {
            key = _key.value,
            value = _value
        });
        _key = null;
    }
    private void remove()
    {
        if (_key == null)
            return;
        dic.remove(dic.first(x => x.key == _key.value));
        _key = null;
    }
}

指定基类

@inherits 指令可用于指定组件的基类。 组件都默认继承了 componentbase 。
示例:
创建文件 testbase.razor ,内容如下

@code{
    protected int id { get; set; }
}

创建 test.razor ,文件内容如下

@inherits testbase
@code{ 
    public int get()
    {
        return id;
    }
}

指定属性

可以通过 @attribute 指令在 razor 组件中指定组件的特性(属性)。 例如页面需要登录才能访问,则添加 [authorize] 。

@page "/"
@attribute [authorize]

导入组件

当要使用的组件与当前组件在同一个命名空间时,不需要“导入”,如果两者不在同一个命名空间,则可以使用 @using 导入此组件。

原始 html

使用 markupstring 类型可以将字符串转为 html 元素对象。

@html

@code{ 
    public markupstring html = (markupstring)"<h1> test </h1>";
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com