Study Blazor .NET(四)数据绑定
阅读原文时间:2021年11月24日阅读:1

翻译自:Study Blazor .NET,转载请注明。

数据绑定

在blazor中单向绑定简单而直接,无需UI刷新或渲染。下面示例展示了单向数据绑定:

//Counter.razor
@page "/counter"

<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

@functions {
    int currentCount = 0;
    void IncrementCount()
    {
        currentCount++;
    }
}

这里 @currentComponent 的值会根据点击 Click me 按钮的次数而增加。<p> 标签元素的值会自动刷新无需任何其它组件刷新。

Blazor为双向绑定提供多种选择,与一些流行的JS语言相比实现起来更加优雅。

相同组件中使用绑定

在blazor中,bind 特性支持双向数据绑定,在下面的例子中,checkbox 在同一个组件中使用了 bind 属性:

//TwoWayBind.razor
@page "/two-way-binding"

<input type="checkbox"
       bind="@updateString" />
<p>This string will get value from above text field : @updateString.ToString()</p>

@functions {
    Boolean updateString {get; set;} = true;
}

双向数据绑定也能用lamda表达式通过 onchange 特性实现。不用担心,Blazor提供了绑定属性的简单方法,更多细节如下:

//TwoWayBind.razor
@page "/two-way-binding"

<input type="text"
       value="@updateString"
       onchange="@((UIChangeEventArgs __e) => updateString = __e.Value.ToString())"/>

<p>This string will get value from above text field: @updateString</p>

@functions {
    string updateString = "";
}

bind 特性可以使用值和事件 bind-value-<onwevent> 进行扩展,上面的示例可以用 oninput 代替 onchange 重写如下:

//TwoWayBind.razor
@page "/two-way-binding"

<input type="text"
       bind-value-oninput="@updateString" />
<p>This string will get value from above text field : @updateString</p>

@functions {
    string updateString = "";
}

不同组件间使用绑定

方法 1

组件之间传递的数据通过组件属性及其属性映射完成,这种方法使用 Action<titem> 数据类型。

//ParentComponent.razor
<h3> Parent Component</h3>
<p>String in Parent: @parentString</p>
<button onclick="@PassToChild">Pass String To Child</button>

<ChildComponent
        ToChild=@parentString
        FromChild=@ReceivedFromChild>
</ChildComponent>

@functions{
    private string parentString = "Initial Parent String";
    private void PassToChild()
    {
        parentString += "- To Child";
    }
    private void ReceivedFromChild(string str)
    {
        parentString = str;
        StateHasChanged();
    }
}


//ChildComponent.razor
<h4>Child Component</h4>
<button onclick="@PassToParent">Pass String to Parent</button>
<p>String received from Parent : @ToChild</p>

@functions{
    [Parameter]
    private string ToChild{get;set;}
    [Parameter]
    Action<string> FromChild{get;set;} 

    private string childString;

    private void PassToParent()
    {
        childString = ToChild + "- To Parent";
        FromChild(childString);
    }
}

ChildComponent中的 FromChild 特性/属性用 Action<string> 类型从子组件向父组件传递值。在父组件中有一个带有 string 类型参数的响应函数,ChildComponent组件中的按钮点击操作触发这个函数,并且反过来通知 PassToParent 函数,为了通知父组件中的状态已经改变,我们使用了Blazor内置函数 StateHasChanged()

方法 2

这种方法使用 EventCallback 数据类型指定事件变更来传递信息从而代替具体的数据,这里不需要再调用 StateHasChanged() 函数。

//ParentComponent.razor
<h3> Parent Component</h3>
<p>Logging Event triggered from Child: @logString</p>

<ChildComponent
        Trigger=@TriggerFromChild>
</ChildComponent>

@functions{
    private string logString = "";
    private void TriggerFromChild(UIMouseEventArgs e)
    {
        logString = e.ToString();
    }
}


//ChildComponent.razor
<h4>Child Component</h4>
<button onclick="@Trigger">Trigger Parent</button>

@functions{
    [Parameter]
    private EventCallback<UIMouseEventArgs> Trigger { get; set; }
}

在ChildComponent中,Trigger 属性回调ParentComponent中相应的带有 UIMouseEventArgs参数的TriggerFromChild 方法,同时在父组件中以字符串形式记录。

下面是支持的事件参数:

  • UIEventArgs
  • UIChangeEventArgs
  • UIKeyboardEventArgs
  • UIMouseEventArgs

方法 3

这里是组件间双向绑定的另一种方法,我们可以基于任何事件/方法的执行手动触发一个 Action

//ParentComponent.razor
<h3> Parent Component</h3>
<p>Logging Event triggered from Child: @logString</p>

<ChildComponent
        EventFromChild=@TriggerFromChild>
</ChildComponent>

@functions{
    private string logString = "";
    private void TriggerFromChild()
    {
        logString = "Triggered From Child using Action and Invoke";
        StateHasChanged();
    }
}


//ChildComponent.razor
<h4>Child Component</h4>
<button onclick="@Trigger">Trigger Parent</button>

@functions{
    [Parameter]
    private Action EventFromChild{get;set;}

    private void Trigger()
    {
        EventFromChild?.Invoke();
    }
}

在ChildComponent中,用内置函数 Invoke 手动触发 EventFromChild Action 属性,同时回调父组件中相应的 TriggerFromChild 方法,在父组件中,通过 StateHasChanged() 通知状态已经改变。

Blazor提供了一种跨越整个RenderTree(所有组件)传递数据的方法,使用 CascadingValueCascadingParameter 代替传递组件特性。传递的值可以被RenderTree (子组件)通过装饰属性 CascadingParameter 代替 Parameter 接收。

//RootComponent.razor
@page "/base-component"
<h3> App Base Component</h3>

<CascadingValue Value="@pName" Name="ProfileName">
    <CascadingValue Value="@pAge" Name="ProfileAge">
        <ParentComponent/>
    </CascadingValue>
</CascadingValue>

@functions {
    private string pName {get;set;} = "New To Blazor";
    private int pAge {get;set;} =  35;
}


//ParentComponent.razor
<h3> Parent Component</h3>
<p> Profile Name is : @Name  and Age is : @Age.ToString(); </p>

@functions{
    [CascadingParameter(Name = "ProfileName")]
    string Name { get; set; }
    [CascadingParameter(Name = "ProfileAge")]
    int Age {get;set;}
}

CascadingParameter 中,Name 参数必须与具有 CascadingValue 组件的 Name 属性匹配,如果我们没有声明 Name,那么 CascadingParameter 中的变量类型与 CascadingValue 中的 Value 属性匹配。

最好声明 Name 参数,以避免混淆,这在应用程序规模增长时很有用。

除了用特性从父组件向子组件传递内容,还可以在组件的 tag 元素中传递内容,并且可以使用 RenderFragment 属性在子组件中呈现。

方式 1

ChildContent 是我们需要在子组件中使用的命名约定,以获取父组件的内容,

//ParentComponent.razor
<h3> Parent Component</h3>
<ChildComponent>
    The line here is passed to child from Parent!!!
</ChildComponent>


//ChildComponent.razor
<h4>Child Component</h4>
<p>@ChildContent</p>

@functions{
    [Parameter]
    private RenderFragment ChildContent { get; set; }
}

方式 2

RenderFragment 主要用于模板化目的,并基于子组件内部的逻辑呈现内容。

//ParentComponent.razor
<h3> Parent Component</h3>
<ChildComponent>
    <SampleText>
        <p>
            <b>Bold Text here!!!</b>
        </p>
    </SampleText>
</ChildComponent>


//ChildComponent.razor
<h4>Child Component</h4>
<div>
    @for(var i = 1; i <= 3; i++)
    {
        <h5>Line No : @i</h5>
        <div>@SampleText</div>
    }
</div>

@functions{
    [Parameter]
    private RenderFragment SampleText { get; set; }
}

此时 SampleText 不是已经存在的组件,它是在父组件中的 ChildComponent tag元素中新生成的,同时在子组件中也声明了相同的命名为 SampleText 的属性。

SampleText 中的文本在子组件里循环渲染3次,这非常有助于创建模板组件、表格等。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章