Study Blazor .NET(四)資料繫結

眼圈黑黑發表於2021-11-23

翻譯自: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次,這非常有助於建立模板元件、表格等。

相關文章