今天我们来看看 Blazor 开发的一些基本知识.
一, Blazor 组件结构
Blazor 中组件的基本结构可以分为 3 个部分, 如下所示:
- //Counter.razor
- //Directives section 指令部分
- @page "/counter"
- //Razor html section Razor HTML 部分
- <h1>Counter</h1>
- <p>Current count: @currentCount</p>
- <button class="btn btn-primary" onclick="@IncrementCount">Click me</button>
- //code sections 功能部分
- @code {
- private int currentCount = 0;
- private void IncrementCount()
- {
- currentCount++;
- }
- }
指令部分:
路由 - @page
DI - @inject
导入库 - @using
Razor HTML 部分:
Razor HTML 语法是 C#代码与 HTML 的结合. 此部分最终在浏览器中呈现.
指令部分:
组件中的函数部分包含用户操作函数(事件方法), 局部变量和从 / 向父 / 子组件传递的属性.
当然如果愿意, 这部分也可以单独写道类文件中.
二, Blazor 的属性和参数
我们看看属性和参数,
- <button id="btnClickMe" class="btn btn-primary" onclick="@IncrementCount">
- Click me
- </button>
在这里, 在按钮元素的 id,class 和 onclick 被称为 HTML 属性.
类似地, 组件的定义方式与 HTML 元素相同,
- //MyDemo.razor
- @page "/myDome"
- <h3>MyDemo</h3>
- <ChildComponent Title="来自 MyDemo"></ChildComponent>
在 Child Component 中, 该属性 Title 与装饰的子组件函数部分中的属性匹配 [Parameter] 关键字.
- //ChildComponent.razor
- //Child Component
- <div>
- <p > 标题 : @Title</p>
- </div>
- @code {
- [Parameter]
- private string Title { get; set; }
- }
运行效果如下:
三, Blazor 的数据绑定
Blazor 的数据绑定同时提供了单向绑定和双向绑定两种机制.
(一)单向绑定:
单向绑定在 Blazor 中简单直接, 无需任何 UI 刷新. 还记得 Counter 示例吗, 他显示了单向数据绑定,
- @page "/counter"
- <h1>Counter</h1>
- <p>Current count: @currentCount</p>
- <button class="btn btn-primary" @onclick="@IncrementCount">Click me</button>
- @code {
- int currentCount = 0;
- void IncrementCount()
- {
- currentCount++;
- }
- }
此处 @currentCount 值根据点击按钮的数量递增 Click me.<p > 标记元素中的值会自动刷新, 无需任何组件刷新.
(二)双向绑定:
在 Blazor 中可以实现双向绑定, 与一些流行的 JS 语言框架相比, Blazor 为双向绑定提供了多种实现方式, Blazor 可以优雅地进行编写.
(1) @bind 属性在 Blazor 中提供双向数据绑定. 下面的示例复选框演示在同一组件中的 bind 属性,
- @page "/myDome"
- <span > 请选择:</span>
- <input type="checkbox" @bind="myChecked" />
- <p > 我选择了 : @myChecked.ToString()</p>
- @code {
- bool myChecked { get; set; } = true;
- }
运行效果如下, 是不是很简单, 很优雅.
再来一个控制样式表的例子看看,
- @page "/myDome"
- <p>
- <span > 显示 / 隐藏:</span>
- <input type="checkbox" @bind="myChecked" />
- </p>
- <p style="display:@(myChecked ?"inline":"none")">看到我了</p>
- @code {
- bool myChecked { get; set; } = true;
- }
(2) @bind 属性在 Blazor 中提供双向数据绑定, 但是只提供了默认的绑定事件, 如果们想在不同的时机触发双向绑定该怎么办呢, 别急同样很简单的, 我们看看下面的代码, 展示了几种绑定实例,
- @page "/myDome"
- <p>
- <span>onchange 方式一</span>
- <input @bind="changeString" />
- </p>
- <p>
- <span>onchange 方式二</span>
- <input type="text"
- value="@changeString"
- @onchange="@((UIChangeEventArgs _e) => changeString = _e.Value.ToString())" />
- </p>
- <p>
- <span>onchange 方式三</span>
- <input @bind-value="changeString" @bind-value:event="onchange" />
- </p>
- <p>
- <span>oninput</span>
- <input @bind-value="changeString" @bind-value:event="oninput" />
- </p>
- <p > 这是我输入的内容: @changeString</p>
- @code {
- string changeString = "";
- }
运行效果如下,
呈现组件时, input 元素 value 的值来自 changeString. 当用户在文本框中键入内容并离开时, 将触发事件 onchange 更改 changeString 的值. 原则上, @bind 将表达式的当前值 value 与 changeString 相关联, 并使用注册的处理程序来处理更改.
除了使用 @bind 语法处理 onchange 事件之外, 还可以通过使用 event 参数 (@bind-value:event) 指定 @bind-value 属性, 使用其他事件来绑定属性或字段. 例如第四个文本框就是绑定 changeString 采用 oninput 事件的属性, 以到达在文本框的值更改时激发.
(三)组件之间绑定:
(1)绑定可识别组件参数, @bind-{property}可在其中跨组件绑定属性值.
- //MyDemo.razor
- @page "/myDome"
- <h1>Parent Component</h1>
- <p > 当前时间: @ParentNow</p>
- <hr />
- <ChildComponent @bind-Now="ParentNow" />
- <hr />
- <button class="btn btn-primary" @onclick="@ChangeTheYear">
更新当前时间
- </button>
- @code {
- [Parameter]
- public DateTime ParentNow { get; set; } = DateTime.Now;
- private void ChangeTheYear()
- {
- ParentNow = DateTime.Now;
- }
- }
- //ChildComponent.razor
- <h2>Child Component</h2>
- <p > 当前时间: @Now</p>
- @code {
- [Parameter]
- public DateTime Now { get; set; }
- [Parameter]
- public EventCallback<DateTime> NowChanged { get; set; }
- }
以上代码中, 子组件 (ChildComponent) 具有一个 Now 组件参数和 NowChanged 回调参数, 父组件 MyDemo 使用 ChildComponent 并将 ParentNow 参数从父级绑定到子组件上 Now 的参数上, 如果通过点击 MyDemo 中的 "更新当前时间" 按钮来更改属性的值, Now 则将更新 ChildComponent 属性, 将新值呈现在 UI 中. 其中, 参数 Now 是可绑定的, 因为它具有 NowChanged 与参数类型匹配的伴随事件. 按照约定, 其等效于
<ChildComponent @bind-Now="ParentNow" @bind-Now:event="NowChanged" />
运行效果:
(2)组件之间传递的数据通过组件属性及其属性映射发生, 此方法使用委托 Action<T > 类型.
- //MyDemo.razor
- @page "/myDome"
- <h3>Parent Component</h3>
- <p > 来自 Child 组件: @childString</p>
- <p>
- <input @bind="inputText" />
- </p>
- <hr />
- <ChildComponent ToChild="@inputText"
- FromChild="@ReceivedFromChild">
- </ChildComponent>
- @code{
- private string inputText = "";
- private string childString = "";
- private void ReceivedFromChild(string str)
- {
- childString = str;
- StateHasChanged();
- }
- }
- //ChildComponent.razor
- <h4>Child Component</h4>
- <p>
- <input @bind="inputText" />
- <button @onclick="@PassToParent">显示到 Parent 组件</button>
- </p>
- <p > 来自 Parent 组件 : @ToChild</p>
- @code{
- [Parameter]
- private string ToChild { get; set; }
- [Parameter]
- Action<string> FromChild { get; set; }
- private string inputText = "";
- private void PassToParent()
- {
- FromChild(inputText);
- }
- }
这里 FromChild 是 ChildComponent 中的属性, 属性使用 Action<string > 数据类型将值从 Child 传递给 Parent Component. 在 Parent 中, 有相应的接收器函数 ReceivedFromChild 和字符串参数, 这将在 ChildComponent 中按钮单击并触发通知时触发 PassToParent, 但是为了通知状态已在父组件中更改, 我们使用 StateHasChanged()的内置 Blazor 函数通知组件其状态已更改.
运行效果如下:
四, 生命周期方法
(1) OnInitializedAsync 和 OnInitialized 方法, 执行代码来初始化组件. 要执行异步操作, 请在操作上使用 OnInitializedAsync 和 await 关键字.
(2)OnParametersSetAsync 和 OnParametersSet 当组件已接收到的参数从其父和值被分配给属性被调用. 这些方法在组件初始化后以及每次呈现组件时执行.
(3)OnAfterRenderAsync 并 OnAfterRender 在组件完成渲染后调用. 此时填充元素和组件引用. 使用此阶段使用呈现的内容执行其他初始化步骤, 例如激活对呈现的 DOM 元素进行操作的第三方 JavaScript 库.
五, 级联值和参数
在某些情况下, 使用组件参数将数据从祖先组件流式传输到附属组件是不方便的, 尤其是在有多个组件层时. 级联值和参数通过提供一种方便的方法, 使上级组件为其所有子代组件提供值. 级联值和参数还提供了一种方法来协调组件.
Blazor 提供了一种在整个 RenderTree(所有组件)中传递数据的方法, 使用 CascadingValue 和 CascadingParameter 不需要传递作为组件属性, 并且可以通过装饰属性 [CascadingParameter] 而不用在 RenderTree(子组件)中接收值[Parameter].
- //MyDemo.razor
- @page "/myDome"
- <p><span > 姓名:</span><input @bind="@pName" /></p>
- <p><span > 年龄:</span><input @bind="@pAge" /></p>
- <hr />
- <CascadingValue Value="@pName" Name="ProfileName">
- <CascadingValue Value="@pAge" Name="ProfileAge">
- <ParentComponent />
- </CascadingValue>
- </CascadingValue>
- @code {
- private string pName { get; set; } = "张三";
- private int pAge { get; set; } = 35;
- }
- //ParentComponent.razor
- <div style="background-color:darkgray">
- <p>Parent Component</p>
- <div style="padding:10px;">
- <ChildComponent />
- </div>
- </div>
- //ChildComponent.razor
- <div style="background-color:beige">
- <p>Child Component</p>
- <p > 输入的 姓名: @Name , 年龄 : @Age.ToString()</p>
- </div>
- @code{
- [CascadingParameter(Name = "ProfileName")]
- string Name { get; set; }
- [CascadingParameter(Name = "ProfileAge")]
- int Age { get; set; }
- }
代码中 MyDemo 的姓名, 年龄穿透 ParentComponent 直接级联到 ChildComponent 中.
在这里 CascadingParameter,Name 参数必须与 Name 带有 CascadingValue 组件的属性匹配, 如果我们没有提到任何 Name, 则 CascadingParameter 中的变量类型与 CascadingValue 中的 Value 属性匹配.
运行效果:
六, 路由
我们在看一个 SPA 中一个基本但很重要的功能路由. 客户端路由可以通过使用 @page 指令装饰组件来在 Blazor 中完成.
- @page "/myDome"
- @page "/myDome/{text}"
@page 在上面的示例中应用了两个指令.
第一个允许在没有参数的情况下导航到组件.
第二个 @page 指令采用{text}route 参数并将值赋给 Text 属性.
好了今天 Blazor 的组件开发就先学习到这, 有意犹未尽的可以查看官方文档深入学习.
posted on 2019-08-15 16:01 燕马越空 阅读(...) 评论(...) 编辑 收藏
来源: https://www.cnblogs.com/liuxtj/p/11350992.html