Blazor學習之旅(5)數據綁定

5bd88dfd863f244841f7bdbb22e93b4b.jpeg

【Blazor】|?總結/Edison Zhou


大家好,我是Edison。

最近在學習Blazor做全棧開發,因此根據老習慣,我會將我的學習過程記錄下來,一來體系化整理,二來作為筆記供將來翻看。

本篇,我們來了解下在Blazor中數據是如何綁定的。

關于數據綁定

如果希望 HTML 元素顯示值,可以編寫代碼來更改顯示內容。如果值發生更改,則需要編寫額外的代碼以更新顯示內容。

在 Blazor 中,可以使用數據綁定將 HTML 元素連接到字段、屬性或表達式。

這樣,當值發生更改時,HTML 元素便會自動更新。更新通常在更改后迅速發生,并且我們無需編寫任何更新代碼。

例如,我們使用@bind指令完成當變量被更改時,h1和input標簽的值也同步更新:

@page "/"<h1>My favorite pizza is: @favPizza</h1><p>Enter your favorite pizza:<input @bind="favPizza" />
</p>@code {private string favPizza { get; set; } = "Margherita"
}

@bind指令比較智能,它大概可以知道你需要綁定標簽的哪個屬性,例如:將其綁定到input標簽時,它會綁定value屬性。而將其綁定到checkbox中,它則自動綁定checked屬性。

將元素綁定到特定事件

默認情況下,@bind指令對于input控件通常會綁定到DOM onchange事件。對于上面的例子來說,當在文本框中輸入了數據時,只有當離開文本框或選擇按下Enter鍵或者Tab鍵,才會觸發DOM onchange事件讓h1標簽的內容發生改變。

假設,我們希望在文本框中輸入任何內容時,都會觸發h1標簽內容的更改。這個事件就不再是DOM onchange事件了而是DOM oninput事件,因此,我們可以借助 @bind-value 和 @bind-value:event 指令來綁定到oninput事件:

@page "/"<h1>My favorite pizza is: @favPizza</h1><p>Enter your favorite pizza:<input @bind-value="favPizza" @bind-value:event="oninput" />
</p>@code {private string favPizza { get; set; } = "Margherita"
}

實現效果:

556bf5e11b7b551905756b10b0e78445.gif

設置綁定值的格式

在很多場景中,我們可能需要對日期進行本地化的格式轉換。這里,我們就可以借助@bind:format指令來指定格式:

@page "/ukbirthdaypizza"<h1>Order a pizza for your birthday!</h1><p>Enter your birth date:<input @bind="birthdate" @bind:format="dd-MM-yyyy" />
</p>@code {private DateTime birthdate { get; set; } = new(2000, 1, 1);
}

此外,我們也可以采用屬性的get/set訪問器來實現自定義的格式轉換,例如下面的示例:

@page "/pizzaapproval"
@using System.Globalization<h1>Pizza: @PizzaName</h1><p>Approval rating: @approvalRating</p><p><label>Set a new approval rating:<input @bind="ApprovalRating" /></label>
</p>@code {private decimal approvalRating = 1.0;private NumberStyles style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;private CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");private string ApprovalRating{get => approvalRating.ToString("0.000", culture);set{if (Decimal.TryParse(value, style, culture, out var number)){approvalRating = Math.Round(number, 3);}}}
}

組件參數的綁定(雙向綁定)

在有些場景中,父組件中嵌套了子組件,我們希望父組件中的變化能夠同步更新到子組件,同理,子組件中的變化能夠同步更新父組件中。實現的方式就是通過組件參數(Parameter),而這個場景也被稱之為鏈式綁定(Chained Bind)。

在Blazor中,我們可以通過 @bind-{PROPERTY} 指令來實現鏈式綁定,其中的 {PROPERTY} 占位符表示要綁定的屬性名字。

例如,我們有以下兩個組件,Parent-1.razor是父組件,其中嵌套了 ChildBind.razor 這個子組件。

ChindBind.razor:

<div class="card bg-light mt-3" style="width:18rem "><div class="card-body"><h3 class="card-title">ChildBind Component</h3><p class="card-text">Child <code>Year</code>: @Year</p><button @onclick="UpdateYearFromChild">Update Year from Child</button></div>
</div>@code {private Random r = new();[Parameter]public int Year { get; set; }[Parameter]public EventCallback<int> YearChanged { get; set; }private async Task UpdateYearFromChild(){await YearChanged.InvokeAsync(r.Next(1950, 2021));}
}

Parent-1.razor:

@page "/parent-1"<h1>Parent Component</h1><p>Parent <code>year</code>: @year</p><button @onclick="UpdateYear">Update Parent <code>year</code></button><ChildBind @bind-Year="year" />@code {private Random r = new();private int year = 1979;private void UpdateYear(){year = r.Next(1950, 2021);}
}

可以看到,這里Parent-1.razor中通過@bind-Year指令與子組件的Year屬性進行了綁定。

需要注意的是,通常情況下,我們還需要設置一個@bing-Year:event指令,不過由于我們定義的事件回調的名字YearChanged是符合自動匹配的,即命名格式是 {PARAMETER NAME}Changed,也就可以省略@bind-Year:event="YearChanged"這個設置,這就是所謂的“約定大于配置”。因此,它其實等價于:

<ChildBind @bind-Year="year" @bind-Year:event="YearChanged" />

因此,我們可以知道,只需要在HTML屬性中加上@bind-{PROPERTY}指令,就是告訴Blazor不僅要將更改到推送到組件,還要觀察組件的任何修改并及時更新自己的狀態。通常來說,這種在父組件和子組件之間的數據綁定 也叫做 雙向綁定。

同時,我們也注意到在Blazor中事件回調(委托)的統一類型為:EventCallback。我們在子組件中使用的是InvokeAsync()方法也說明它是線程安全的。

實現效果:

873ce2b26bfdbf78d4acaf4f0918bc33.gif

在一個更真實常見的場景中,我們可能希望實現數據實施修改的聯動更新,類似于下面的例子。

PasswordEntry.razor:

<div class="card bg-light mt-3" style="width:22rem "><div class="card-body"><h3 class="card-title">Password Component</h3><p class="card-text"><label>Password:<input @oninput="OnPasswordChanged"requiredtype="@(showPassword ? "text" : "password")"value="@password" /></label><span class="text-danger">@validationMessage</span></p><button class="btn btn-primary" @onclick="ToggleShowPassword">Show password</button></div>
</div>@code {private bool showPassword;private string? password;private string? validationMessage;[Parameter]public string? Password { get; set; }[Parameter]public EventCallback<string> PasswordChanged { get; set; }private Task OnPasswordChanged(ChangeEventArgs e){password = e?.Value?.ToString();if (password != null && password.Contains(' ')){validationMessage = "Spaces not allowed!";return Task.CompletedTask;}else{validationMessage = string.Empty;return PasswordChanged.InvokeAsync(password);}}private void ToggleShowPassword(){showPassword = !showPassword;}
}

PasswordBinding.razor:

@page "/password-binding"<h1>Password Binding</h1><PasswordEntry @bind-Password="password" /><p><code>password</code>: @password
</p>@code {private string password = "Not set";
}

最終效果:

3f271f8325603f5eb97986ef4e18108b.gif

組件參數綁定的最佳實踐

我們可以在多層嵌套的組建中綁定組件參數,但是我們必須遵循這類單向數據綁定的流程:

  • 更改通知是逐級向上流動

  • 新的參數值是逐級向下流動

一個推薦的方式是只在父組件中存儲源數據,以此避免在狀態需要更新時容易產生的混淆。

例如,下面這個例子:

Parent2.razor:

@page "/parent-2"<h1>Parent Component</h1><p>Parent Message: <b>@parentMessage</b></p><p><button @onclick="ChangeValue">Change from Parent</button>
</p><NestedChild @bind-ChildMessage="parentMessage" />@code {private string parentMessage = "Initial value set in Parent";private void ChangeValue(){parentMessage = $"Set in Parent {DateTime.Now}";}
}

NestedChild.razor:

<div class="border rounded m-1 p-1"><h2>Child Component</h2><p>Child Message: <b>@ChildMessage</b></p><p><button @onclick="ChangeValue">Change from Child</button></p><NestedGrandchild @bind-GrandchildMessage="BoundValue" />
</div>@code {[Parameter]public string? ChildMessage { get; set; }[Parameter]public EventCallback<string> ChildMessageChanged { get; set; }private string BoundValue{get => ChildMessage ?? string.Empty;set => ChildMessageChanged.InvokeAsync(value);}private async Task ChangeValue(){await ChildMessageChanged.InvokeAsync($"Set in Child {DateTime.Now}");}
}

NestedGrandchild.razor:

<div class="border rounded m-1 p-1"><h3>Grandchild Component</h3><p>Grandchild Message: <b>@GrandchildMessage</b></p><p><button @onclick="ChangeValue">Change from Grandchild</button></p>
</div>@code {[Parameter]public string? GrandchildMessage { get; set; }[Parameter]public EventCallback<string> GrandchildMessageChanged { get; set; }private async Task ChangeValue(){await GrandchildMessageChanged.InvokeAsync($"Set in Grandchild {DateTime.Now}");}
}

從示例中可以看出,它遵循了兩個原則:

(1)源數據是自頂向下流動,即parentMessage 和 BoundValue 兩個值。

(2)事件通知是自底向上流動,即子組件的ChangeValue方法都會調用EventCallback來向上通知。

最終效果:

8bb49d3f011e00712db090e8546623bd.gif

小結

本篇,我們了解了數據如何在Blazor中進行數據的綁定。

下一篇,我們學習一下在Blazor中數據綁定的各種花樣。

參考資料

Microsoft Docs,《與Blazor Web應用中的數據交互》

Microsoft Docs,《Blazor數據綁定》

236dc049ae7e4c423724172596c339c4.gif

年終總結:Edison的2021年終總結

數字化轉型:我在傳統企業做數字化轉型

C#刷題:C#刷劍指Offer算法題系列文章目錄

.NET面試:.NET開發面試知識體系

.NET大會:2020年中國.NET開發者大會PDF資料

fb0b67a1e789c06e786a00ba6b442c19.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281894.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281894.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281894.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

chrome開啟touch屏幕點擊事件

2019獨角獸企業重金招聘Python工程師標準>>> 在chrome瀏覽器輸入 chrome://flags/#top-chrome-md 找到屬性 UI Layout for the browsers top chrome 選擇Hybrid&#xff0c;重啟chrome&#xff0c;如下圖&#xff1a; 轉載于:https://my.oschina.net/swingcoder/blo…

安卓如何更換wps黑金會員圖標_wps圖標(手機wps會員圖標黑色)

嘗試右鍵文件--打開方式--選擇默認程序,選擇wps程序,勾選始終以選擇的程序打開此文件,確定。如果還是不行的話,請嘗試做以下操作:點擊桌面左下角開始按鈕--在. 在WPS演示中,單擊“項目符號”,找到對應的那個即可。在WPS文字中,也是如此。 如題,如何做一個圖表,分別表…

Linux服務器重啟后crs_stat -t 命令無法正常使用以及解決思路

前提&#xff1a;在Linux系統中安裝ASM&#xff0c;安裝完ASM和Oracle數據庫時都是正常使用的&#xff0c;但在重啟服務器后Oracle相關命令不識別。1、[gridudevasm:/home/grid]$crsctl status res -t -bash: crsctl: command not found2、查看環境變量是否正常&#xff0c;命令…

英語十六個時態總結

下面用表格的形式給羅列出來&#xff0c;便于記憶 英語共有十六種時態&#xff0c;其表現形式如下(以study為例)&#xff1a; 一般時 進行時 完成時 完成進行時 現在 studystudies am studyingis studyingare studying have studiedhas studied have been studyinghas …

Python基礎--Python3基礎語法

Python3 基礎語法編碼默認情況下&#xff0c;Python3源碼文件以UTF-8編碼&#xff0c;所有字符串都是Unicode字符串。當然也可以為源碼文件指定不同的編碼&#xff0c;例如&#xff1a;# -*- coding: cp-1252 -*-標識符1.第一個字符必須是字母表中字母或下劃線&#xff1b;2.標…

3 Python os 文件和目錄

ile 對象使用 open 函數來創建&#xff0c;下表列出了 file 對象常用的函數&#xff1a; 序號方法及描述1 file.close() 關閉文件。關閉后文件不能再進行讀寫操作。 2 file.flush() 刷新文件內部緩沖&#xff0c;直接把內部緩沖區的數據立刻寫入文件, 而不是被動的等待輸出緩沖…

python 打開某個exe_python定時檢查啟動某個exe程序(如果exe掛了)

詳見代碼如下&#xff1a;import threadingimport timeimport osimport subprocessdef get_process_count(imagename):p os.popen(tasklist /FI "IMAGENAME eq %s" % imagename)return p.read().count(imagename)def timer_start():t threading.Timer(120,watch_fu…

redis系列3---理解內存

理解內存 為什么要理解內存呢&#xff1f;redis所有的數據都存在內存中如何高效利用內存&#xff0c;實現用更少的內存存更多的數據&#xff0c;從而降低成本 如何統計內存使用&#xff1f;info memory可以獲取內存相關指標&#xff0c;如下&#xff1a;used_memory&#xff1a…

Google發布了Tensorflow Lite,用于移動電話的神經網絡庫

Google的工程副總Dave Burke宣布了一個專門針對移動電話而優化的Tensorflow新版本。\\這一新的軟件庫稱為Tensorflow Lite&#xff0c;允許開發人員在用戶的移動電話上實時地運行人工智能應用。據Burke介紹&#xff0c;該庫在設計上力求更快和更小的同時&#xff0c;依然支持最…

4. ZooKeeper 基本操作

ZooKeeper的數據模型及其API支持以下九個基本操作&#xff1a; 操作描述create在ZooKeeper命名空間的指定路徑中創建一個znodedelete從ZooKeeper命名空間的指定路徑中刪除一個znodeexists檢查路徑中是否存在znodegetChildren獲取znode的子節點列表getData獲取與znode相關的數據…

byte java byte_詳解java中的byte類型

Java中整數類型有:byte占8位, short 占16位, int占32位, long占64位Java也提供了一個byte數據類型&#xff0c;并且是基本類型中的整數類型。java byte是作為最小的數字來處理的&#xff0c;因此它的值域被定義為-128~127&#xff0c;也就是signed byte。下面這篇文章主要給大家…

zabbix 3.0.0beta1安裝-centos6.8版本

zabbix 3.0安裝 zabbix最低需要mysql 5.5 php5.3 查詢mysql版本yum list installed | grep mysql##mysql-libs.x86_64 5.1.73-5.el6_6 anaconda-CentOS-201508042137.x86_64/6.7 卸載mysqlyum remove mysql* 指定mysql源rpm -ivh http://dev.mysql.com/get/mysql-community-rel…

技術走向管理一些思考

在《IT項目管理》一書中針對IT行業定義了一個新的“工種”--多才多藝者&#xff0c;并預言未來的IT產業中多才多藝者的重要性將逐漸凸顯。多才多藝者即是具有技術背景&#xff0c;同一時候了解業務部門、能規劃和實施IT計劃、添加商業價值、培養公司內外部關系的人。 想想還認為…

npm 安裝 chromedriver 失敗的解決辦法

https://segmentfault.com/a/1190000008310875 npm install chromedriver --chromedriver_cdnurlhttp://cdn.npm.taobao.org/dist/chromedriver轉載于:https://www.cnblogs.com/chenxijywc/p/7825024.html

微軟正式發布Azure Functions 2.0

微軟正式發布Azure Functions的第二個版本&#xff0c;這是一個事件驅動的、按需計算的Azure平臺服務。與版本1相比&#xff0c;新版本的Azure Functions包含的多項特性使開發人員可以更輕松地構建可伸縮的無服務器應用程序。2016年初&#xff0c;微軟首次推出Azure Functions預…

CSS-下拉導航條

Web網站中很多時候都會出現下拉導航條&#xff0c;有的是通過CSS實現&#xff0c;有的通過JavaScript插件實現&#xff0c;其實CSS實現起來比較簡單,先來看一個簡版的下拉菜單: Html代碼通過ul列表實現: 123456789101112131415161718<ul class"nav"> <li>…

#UnityTips# 2017.11.14

hi&#xff0c;all。最近比較忙&#xff0c;所以更新也比較慢了。 今天就來和大家分享一個小Tip&#xff0c;它是關于UGUI的坑的。 使用過UGUI的朋友們都知道&#xff0c;Canvas的渲染方式有三種&#xff1a; Screen Space OverlayScreen Space CameraWorld Space其中后兩者都需…

細聊.Net Core中IServiceScope的工作方式

前言自從.Net Core引入IOC相關的體系之后&#xff0c;關于它的討論就從來沒有停止過&#xff0c;因為它是.Net Core體系的底層框架&#xff0c;你只要使用了.Net Core的時候就必然會用到它。當然關于使用它的過程中產生的問題也從來沒停止過。我對待問題的態度向來都是&#xf…

WPF 獲取鼠標屏幕位置、窗口位置、控件位置

原文:WPF 獲取鼠標屏幕位置、窗口位置、控件位置public struct POINT{public int X;public int Y;public POINT(int x, int y){this.X x;this.Y y;}}[DllImport("user32.dll")] public static extern bool GetCursorPos(out POINT lpPoint);//e.GetPosition(this);…

java 復制excel_Java 復制Excel工作表

本文歸納了關于Java如何復制Excel工作表的方法&#xff0c;按不同復制需求&#xff0c;可分為&#xff1a;1. 復制工作表1.1 在同一個工作簿內復制工作表1.2 在不同工作簿間復制工作表2. 復制指定單元格數據對于復制方法copy()&#xff0c;這里簡單整理了一個表格&#xff0c;其…