组件参数
组件可以具有组件参数,这些参数是使用具有该属性的组件类上的private非公共属性定义的[Parameter]
。使用属性为标记中的组件指定参数。
ParentComponent父组件:
@page "/ParentComponent"
<h1>parent-child example</h1>
<ChildComponent Title="Panel Title from Parent" onClick="@ShowMessage">
Content of the child component is supplied by the parent component.
子组件的内容由父组件提供。
</ChildComponent>
<p><b>@messageText</b></p>
@functions{
private string messageText;
private void ShowMessage(UIMouseEventArgs e)
{
messageText = "Blaze a new trail with Blazor!";
}
}
ChildComponent子组件:
<div class="panel panel-default">
<div class="panel-heading">@Title</div>
<div class="panel-body">@ChildContent</div>
<button class="btn btn-primary" onclick="@onClick">
触发一个父组件的方法
</button>
</div>
@functions{
[Parameter]
private string Title { get; set; }
[Parameter]
private RenderFragment ChildContent { get; set; }//调用组件的内容
[Parameter]
private EventCallback<UIMouseEventArgs> onClick { get; set; }//事件
}
注意:接收RenderFragment
内容的属性名必须是:ChildContent,否则不能正确运行。
数据绑定
使用该bind
属性完成对组件和DOM元素的数据绑定。以下示例将_italicsCheck
字段绑定到复选框的已检查状态:
<input type="checkbox" class="form-check-input" id="italicsCheck"
bind="@_italicsCheck" />
选中并清除该复选框后,属性的值将分别更新为true
和false
。
由于组件在事件处理程序代码执行后呈现自身,因此属性更新通常会立即反映在UI中。
格式字符串
数据绑定与DateTime格式字符串一起使用。其他格式表达式(例如货币或数字格式)目前不可用。
<input bind="@StartDate" format-value="yyyy-MM-dd" />
@functions {
[Parameter]
private DateTime StartDate { get; set; } = new DateTime(2020, 1, 1);
}
组件参数
bind-{property}
可以跨组件绑定属性值。
@page "/ParentComponent2"
<h1>Parent Component</h1>
<p>Parent Component</p>
<p>ParentYear:@ParentYear</p>
<ChildComponent2 bind-Year="@ParentYear"/>
<button class="btn btn-primary" onclick="@ChangeTheYear">
Change Year to 1986
</button>
@functions{
[Parameter]
private int ParentYear { get; set; } = 1987;
private void ChangeTheYear()
{
ParentYear = 1986;
}
}
<h2>Child Component</h2>
<p>Year:@Year</p>
@functions{
[Parameter]
private int Year { get; set; }
[Parameter]
private EventCallback<int> YearChanged { get; set; }
}
该Year
参数是可绑定的,因为它具有YearChanged
与Year
参数类型匹配的伴随事件。
按照惯例,<ChildComponent bind-Year="@ParentYear" />
基本上相当于写作,
<ChildComponent bind-Year-YearChanged="@ParentYear" />
通常,可以使用bind-property-event
attribute将属性绑定到相应的事件处理程序。
事件处理
对于命名HTML元素属性on<event>
(例如,onclick
,onsubmit
)与一个代表类型值,剃刀部件把该属性的值作为事件处理程序。属性的名称始终以on
。开头。
UpdateHeading
在UI中选择按钮时,以下代码调用该方法:
<button class="btn btn-primary" onclick="@UpdateHeading">
Update heading
</button>
@functions {
private void UpdateHeading(UIMouseEventArgs e)
{
...
}
}
CheckboxChanged
在UI中更改复选框时,以下代码调用该方法:
<input type="checkbox" class="form-check-input" onchange="@CheckboxChanged" />
@functions{
private string displayValue = string.Empty;
private void CheckboxChanged(UIChangeEventArgs e)
{
displayValue=Convert.ToBoolean(e.Value)?"是":"否";
}
}
事件处理程序也可以是异步的并返回Task。无需手动呼叫StateHasChanged()
。发生异常时会记录异常。
<button class="btn btn-primary" onclick="@UpdateHeading">
Update heading
</button>
@functions {
private async Task UpdateHeading(UIMouseEventArgs e)
{
...
}
}
对于某些事件,允许使用特定于事件的事件参数类型。如果不需要访问其中一种事件类型,则在方法调用中不需要它。
支持的事件参数列表是:
- UIEventArgs
- UIChangeEventArgs
- UIKeyboardEventArgs
- UIMouseEventArgs
使用Lambda表达式:
<h1>@message</h1>
@for(var i=1;i<4;i++)
{
var buttonNumber = i;
//使用buttonNumber而不能使用循环i
<button class="btn btn-primary" onclick="@(e=>UpdateHeading(e,buttonNumber))">
Button #@i
</button>
}
@functions{
private string message = "Select a button to learn its position.";
private void UpdateHeading(UIMouseEventArgs e,int buttonNumber)
{
message = $"You selected Button #{buttonNumber} at " + $"mouse position:{e.ClientX} X {e.ClientY}.";
}
}
EventCallback
嵌套组件的常见场景是希望在子组件事件发生时运行父组件的方法
要在组件之间公开事件,请使用EventCallback
。父组件可以将回调方法分配给子组件EventCallback
。
<div class="panel panel-default">
<div class="panel-heading">@Title</div>
<div class="panel-body">@ChildContent</div>
<button class="btn btn-primary" onclick="@OnClick">
Trigger a Parent component method
</button>
</div>
@functions{
[Parameter]
private string Title { get; set; }
[Parameter]
private RenderFragment ChildContent { get; set; }
//使用组件时,对外公开的事件
[Parameter]
private EventCallback<UIMouseEventArgs> OnClick { get; set; }
}
@page "/ParentComponent2"
<h1>Parent-child example</h1>
@* 使用组件,将方法委托给子组件,方法由子组件中的点击事件触发 *@
<ChildComponent2 Title="Panel Title from Parent" OnClick="@ShowMessage">
Content of the child component is supplied by the parent component.
</ChildComponent2>
<p><b>@messageText</b></p>
@functions{
private string messageText;
private void ShowMessage(UIMouseEventArgs e)
{
messageText = "Blaze a new trail whith Blazor!";
}
}
属性引用组件实例
组件引用提供了一种引用组件实例的方法,以便您可以调用该实例的方法。
要捕获组件引用,请将ref
属性添加到子组件,然后定义与子组件具有相同名称和相同类型的字段。
@* 将子组件定义为用属性可以引用的实例 *@
<MyLoginDialog ref="loginDialog"/>
<button class="btn btn-primary" onclick="@OnSomething">Button</button>
@functions{
//属性类型和子组件类型一致,属性名称和子组件调用ref的名称一致
private MyLoginDialog loginDialog;
private void OnSomething()
{
loginDialog.Show();//在组件实例上调用.NET方法。
}
}
<h1>MyLoginDialog</h1>
<p>@msg</p>
@functions{
private string msg = string.Empty;
public void Show()
{
msg = "Show() 被调用";
StateHasChanged();//如果不调用此方法,当子组件变化时,不会重新刷新UI,即将看不到变化
}
}
呈现组件时,将loginDialog
使用MyLoginDialog
子组件实例填充该字段。然后,您可以在组件实例上调用.NET方法。
注意:千万不能使用组件引用改变子组件的状态。而是使用常规声明性参数将数据传递给子组件。这样子组件自动在正确的时间重新渲染。
生命周期方法
组件初始化:
重载OnInitAsync和
OnInit方法
执行代码来初始化组件。要执行异步操作,请在操作上使用OnInitAsync
和await
关键字:
protected override async Task OnInitAsync()
{
await ...
}
同步操作,请使用OnInit
:
protected override void OnInit()
{
...
}
组件参数初始化:
OnParametersSetAsync
和OnParametersSet
当组件已接收到的参数后调用。这些方法在组件初始化后以及每次呈现组件时执行:
protected override async Task OnParametersSetAsync()
{
await ...
}
protected override void OnParametersSet()
{
...
}
组件完成渲染后调用
OnAfterRenderAsync
并OnAfterRender
在组件完成渲染后调用。此时填充元素和组件引用。使用此阶段使用呈现的内容执行其他初始化步骤,例如激活对呈现的DOM元素进行操作的第三方JavaScript库。
protected override async Task OnAfterRenderAsync()
{
await ...
}
protected override void OnAfterRender()
{
...
}
SetParameters
可以重写以在设置参数之前执行代码:
public override void SetParameters(ParameterCollection parameters)
{
...
base.SetParameters(parameters);
}
如果base.SetParameters
未调用,则自定义代码可以以任何所需方式解释传入参数值。例如,不需要将传入参数分配给类上的属性。
ShouldRender
可以重写以禁止刷新UI。如果实现返回true
,则刷新UI。即使ShouldRender
被覆盖,组件也始终最初呈现。
protected override bool ShouldRender()
{
var renderUI = true;
return renderUI;
}
使用IDisposable处理组件
如果组件实现了IDisposable,则在从UI中删除组件时将调用Dispose方法。以下组件使用@implements IDisposable
和Dispose
方法:
@using System
@implements IDisposable
...
@functions {
public void Dispose()
{
...
}
}
路由
Blazor中的路由是通过为应用程序中的每个可访问组件提供路由模板来实现的。
@page
编译带有指令的Razor文件时,会为生成的类指定RouteAttribute,指定路径模板。在运行时,路由器使用a查找组件类,RouteAttribute
并呈现任何组件具有与请求的URL匹配的路由模板。
可以将多个路径模板应用于组件。以下组件响应的请求/BlazorRoute
和/DifferentBlazorRoute
:
@page "/BlazorRoute"
@page "/DifferentBlazorRoute"
<h1>Blazor routing</h1>
路由参数
组件可以从@page
指令中提供的路由模板接收路由参数。路由器使用路由参数填充相应的组件参数。
路由参数组件:
@page "/RouteParameter"
@page "/RouteParameter/{text}"
<h1>Blazor is @Text!</h1>
@functions {
[Parameter]
private string Text { get; set; } = "fantastic";
}
不支持可选参数,因此@page
在上面的示例中应用了两个指令。第一个允许在没有参数的情况下导航到组件。第二个@page
指令采用{text}
route参数并将值赋给Text
属性。