網站首頁 編程語言 正文
項目 Blazor 中,使用?.razor
?結尾的文件,稱為組件;而 Blazor 中的組件,正式名稱是?razor 組件;
Blazor 組件是 razor 過渡而來的,使用 razor 的基本語法特性,但是 Balzor 不支持 razor 中的標記幫助程序。
關于組件
.razor
?文件分為頁面(帶@page
)和組件(不帶@page
,或者說頁面組件和非頁面組件。兩者區別在于頁面有路由,可以直接通過 URI 訪問,一般放在 Page 文件夾中;而組件,作為一個部件,必須嵌入其它組件中,在頁面中顯示,一般放到 Shared 文件夾中,供多個頁面共享、復用。
本文接下來所指的組件都是非頁面組件。.razor
?文件中,開頭有?@page
?標記的,就是頁面組件,沒有的就是非頁面組件。
當然兩者并沒有嚴格的區分。
組件命名時,應該帶上?Component
?后綴。
組件類
每個?.razor
?文件,在編譯后會生成一個類,稱為組件類。 生成的類的名稱與文件名匹配。
因此,每個?.razor
?文件,必須以大寫字母開頭,按照類名命名規范定義文件名稱。
`.razor` ,以 `@code{}` 包含 C# 代碼,這部分代碼除了組件間可以使用,程序中也可以正常使用,因為屬于類的一部分。
創建?Test.razor
?文件,文件內容如下:
@code{ public string Name { get; set; } }
Pargrom 中:
Pages.Test test = new Pages.Test(); test.Name = "Blazor";
簡單來說,就是可以作為一個類來使用。@code{}
?中定義的成員,就是類的成員。
成員正常使用 public 、private 等訪問修飾符修飾。
靜態資產
默認靜態資源文件位置在項目的 wwwroot 目錄,前端(.razor、.cshtml)等,默認尋址時,使用絕對路徑?/
?即可訪問資源。
例如:
<img alt="Company logo" src="/images/logo.png" />
這個路徑是要放到前端才能,由前端訪問時 ASP.NET Core 框架自動處理,相當于前端訪問?/
?,后端訪問?D:/test/Blazor/wwwroot
。
路由與路由參數
頁面組件使用?@page
?設置此頁面的訪問地址,這里沒有 Controller 和 Action 的分層和路由導航(相對地址),直接是一個絕對的訪問地址,并且全局唯一。
Index.razor
?中,路由:
@page "/"
Blazor 不支持像 Controller 和 Action 那樣設置靈活的 URL 可選參數(URL Query),例如:
[HttpGet("Test/{Id}")] public string Test([FromQuery]int Id) { return "123"; }
Blazor 如果想通過 URL Query 傳遞參數,可以使用?{
Name}
:
@page "/test" @page "/test/{Id}" <h2>@Id</h2> @code{ [Parameter] public string Id { get; set; } = "123"; }
因為 Blazor 不支持可選參數,因此,如果只設置?@page "/test/{Id}"
,那么每次訪問都必須帶有這個參數值。
需要使用?[Parameter]
?來修飾成員,才能捕獲?@page "/test/{Id}"
。
另外,理由參數是 string 類型,不能自動轉為數值類型。不如會報錯:
InvalidOperationException: Unable to set property 'Id' on object of type 'BlazorApp1.Pages.Test'. The error was: Unable to cast object of type 'System.String' to type 'System.Int32'.
你可以接收后,顯式轉為數值類型。
組件參數
在?@code
?代碼塊中,使用?[Parameter]
?修飾的公共屬性,那么這個屬性就會標識為組件指定參數。
注意官網文檔中,這個小節的代碼示例,實際是不允許這樣寫得的。
目前,有兩個地方需要使用?[Parameter]
?特性,一個是前一小節的路由參數綁定,另一個是嵌入組件時使用。
示例:
Test.razor 文件內容:
<h2>@Title</h2> @code{ [Parameter] public string Title { get; set; } = "test"; }
別的組件嵌入?Test.razor
?這個組件時,就可以使用 Title 傳遞參數進去:
<Test Title="111" />
請勿創建會寫入其自己的組參數屬性的組件
前面我們說到,?[Parameter]
?特性的使用,這個特性時作為參數傳遞而使用的。
對于路由參數,其修飾的屬性應該是?privite
,對于其它組件傳遞參數,屬性應該設置為?public
。
如果一個組件的?@code{}
?成員不需要被外界作為參數使用,就應該設置為?private
。
因為?.razor
?一般不會作為類來使用。、;而且不設置?[Parameter]
?的屬性,別的組件也使用不了這個屬性。
那么,文檔說 “請勿創建會寫入其自己的組參數屬性的組件”,指定是?[Parmeter]
?休息的屬性,是作為參數傳遞使用的,不要在組件中修改這個屬性的值。
如果實在要操作的話,可以先拷貝這個值,使用別的變量操作,示例:
<h2>@Title</h2> @code{ [Parameter] public string Title { get; set; } = "test"; private string _Title; protected override void OnInitialized() { _Title = Title; } }
這樣,組件要操作的話,可以使用?_Title
?,保留?Title
。OnInitalized()
?是一個組件初始化的方法,也可以理解成構造函數,可以參考?https://docs.microsoft.com/zh-cn/aspnet/core/blazor/lifecycle?view=aspnetcore-3.1#component-initialization-methods
子內容
因為組件是可以嵌套的,可以要求另一個組件顯示要求的內容。
- 被多個組件使用,不同組件要呈現不一樣的內容;
- 要根據父組件的配置,顯示子組件;
- 組件 A 要求使用到的組件 B,顯示其傳遞的內容;
簡單來說,就是將頁面內容作為復雜類型傳遞給另一個組件,要求這個組件顯示出來。
那么,子內容指的是一個組件可以接收另一個組件的內容,使用?RenderFragment
?來接收內容。
示例如下:Test.razor
?中,內容:
<div>@Children</div> @code{ [Parameter] public RenderFragment Children { get; set; } }
另一個組件:
@page "/" <Test Children=r /> @code{ private RenderFragment r =@<h1>測試子內容</h1>; }
RenderFragment
?的使用,請自行查閱資料。
屬性展開
屬性展開是使用字典類型表示一個 Html 標簽的多個屬性。
<input id="1" maxlength="@Maxlength" placeholder="@Placeholder" required="@Required" size="@Size" /> <input id="2" @attributes="InputAttributes" /> @code { #region private string Maxlength { get; set; } = "10"; private string Placeholder { get; set; } = "Input placeholder text"; private string Required { get; set; } = "required"; private string Size { get; set; } = "50"; #endregion // 使用字典鍵值對表示 public Dictionary<string, object> InputAttributes { get; set; } = new Dictionary<string, object>() { { "maxlength", "10" }, { "placeholder", "Input placeholder text" }, { "required", "required" }, { "size", "50" } }; }
任意參數
[Paramter]
?特性,只有一個屬性,其定義如下:
public bool CaptureUnmatchedValues { get; set; }
文檔說明:[Parameter] 上的 CaptureUnmatchedValues 屬性允許參數匹配所有不匹配任何其他參數的特性。
其作用是通過字典接收在父組件中出現但是未在?@code{}
?中定義的參數屬性。
例如:Test.razor
?中
@code{ // 這個屬性沒有用,隨便起個名字測試 [Parameter] public string A { get; set; } [Parameter(CaptureUnmatchedValues = true)] public IDictionary<string, object> AdditionalAttributes { get; set; } }
父組件中使用:
<Test A="A" B="B" C="C" />
B、C 都是?Test.razor
?中沒有出現過的,那么這些參數和參數值都會自動轉為鍵值對存儲到 AdditionalAttributes 中。
測試示例:Test.razor
?中的內容
<ul> @foreach (var item in AdditionalAttributes) { <li>@item.Key - @item.Value</li> } </ul> @code{ // 這個屬性沒有用,隨便起個名字測試 [Parameter] public string TTT { get; set; } [Parameter(CaptureUnmatchedValues = true)] public IDictionary<string, object> AdditionalAttributes { get; set; } }
其它組件使用:
@page "/" <Test TTT="ces" id="useIndividualParams" maxlength="10" placeholder="Input placeholder text" required="required" size="50" />
捕獲對組件的引用
組件引用提供了一種引用組件實例的方法,使用?@ref
?可以實現引用對參數的引用。
創建一個?Test.razor
?文件,內容不限。
在一個組件中,引用該組件實例
@page "/" <Test @ref="_test" /> @code{ private Test _test; }
在使用?Test.razor
?組件的同時,保留了引用,以便在?@code{}
?中使用其成員。
在外部調用組件方法以更新狀態
組件繼承了 ComponentBase 類型,有個?InvokeAsync
?方法可用于外界更新此 UI 的狀態。
示例如下:
創建 MyUIServer 類型,
// 能夠向所有正在打開的 Index.razor 頁面發送通知 public static class MyUIServer { // 向所有人發送通知 public static async Task ToMessage(string message) { if (events != null) { await events.Invoke(message); } } public static void AddEvent(Func<string, Task> func) { events += func; } public static void RemoveEvent(Func<string, Task> func) { events -= func; } private static event Func<string, Task> events; }
在?Index.razor
?中
@page "/" @using BlazorApp1.Data @implements IDisposable <input @bind="_message" /> <button @onclick="Btn">發送消息</button> <ul> @foreach (var item in messageList) { <li>@item</li> } </ul> @code { private string _message; private List<string> messageList = new List<string>(); // 進入頁面時 protected override void OnInitialized() { MyUIServer.AddEvent(UIEvent); } // 退出當前頁面UI后移除該事件 public void Dispose() { MyUIServer.RemoveEvent(UIEvent); } protected async Task UIEvent(string message) { // 組件自帶的方法,用于外部調用更新狀態 await InvokeAsync(() => { messageList.Add(message); StateHasChanged(); }); } // 向所有正在訪問 Index.razor 頁面發送消息 private async Task Btn() { await MyUIServer.ToMessage(_message); } }
打開多個窗口,訪問頁面?https://localhost:5001/
,在其中一個窗口輸入內容并且點擊按鈕,即可將消息內容推送到其它窗口。
下面是一個修改官網示例的示例:
創建一個類型 NotifierService
public class NotifierService { public async Task Update(string key, int value) { if (Notify != null) { await Notify.Invoke(key, value); } } public event Func<string, int, Task> Notify; }
該類型的 Notify 可以綁定多個事件;通過調用?Update()
?方法,可以觸發各個事件。
在 Startup 中注入服務?services.AddSingleton<NotifierService>();
。Index.razor
?中,內容為:
@page "/" @using BlazorApp1.Data @inject NotifierService Notifier @implements IDisposable <p>Last update: @_lastNotification.key = @_lastNotification.value</p> @code { private (string key, int value) _lastNotification; protected override void OnInitialized() { Notifier.Notify += OnNotify; } public async Task OnNotify(string key, int value) { // 組件自帶的方法,用于外部調用更新狀態 await InvokeAsync(() => { _lastNotification = (key, value); StateHasChanged(); }); } // 退出當前頁面UI后移除該事件 public void Dispose() { Notifier.Notify -= OnNotify; } }
Test.razor
?文件中:
@page "/test" @using BlazorApp1.Data @inject NotifierService Notifier Key: <input @bind="Key" /> Value: <input @bind="Value" /> <button @onclick="Update">更新</button> @code{ private string Key { get; set; } private int? Value { get; set; } private async Task Update() { await Notifier.Update(Key, Value.Value); Key = string.Empty; Value = null; } }
然后啟動項目,一個頁面打開?https://localhost:5001/
?,另一個頁面打開?https://localhost:5001/test
。
在?test
?頁面輸入 Key 和 Value,點擊按鈕,即可通知到所有正在打開?Index.razor
?的頁面。
使用 @ 鍵控制是否保留元素和組件
在使用表格或了表等元素時,如果出現插入或刪除、更新等情況,整個表格或列表,就會被重新渲染。這樣會帶來比較大的性能消耗。
一般使用綁定的元素,其更新是自動的,不需要人為控制。
在能保證每一項的某個元素列,都是唯一的時候,我們可以使用?@key
?關鍵字來優化組件。
示例:
@page "/" @using BlazorApp1.Data Key: <input @bind="_key" /> Value: <input @bind="_value" /> <button @onclick="Add">添加</button> <button @onclick="Remove">移除</button> <ul> @foreach (var item in dic) { <li @key="item.Key">@item.Key - @item.Value</li> } </ul> @code { private int? _key; private int _value; private List<MyData> dic { get; set; } = new List<MyData>(); private void Add() { if (_key == null) return; dic.Add(new MyData { Key = _key.Value, Value = _value }); _key = null; } private void Remove() { if (_key == null) return; dic.Remove(dic.First(x => x.Key == _key.Value)); _key = null; } }
指定基類
@inherits
?指令可用于指定組件的基類。 組件都默認繼承了 ComponentBase 。
示例:
創建文件?TestBase.razor
?,內容如下
@code{ protected int Id { get; set; } }
創建?Test.razor
?,文件內容如下
@inherits TestBase @code{ public int Get() { return Id; } }
指定屬性
可以通過 @attribute 指令在 Razor 組件中指定組件的特性(屬性)。 例如頁面需要登錄才能訪問,則添加?[Authorize]
?。
@page "/" @attribute [Authorize]
導入組件
當要使用的組件與當前組件在同一個命名空間時,不需要“導入”,如果兩者不在同一個命名空間,則可以使用?@using
?導入此組件。
原始 HTML
使用 MarkupString 類型可以將字符串轉為 HTML 元素對象。
@html @code{ public MarkupString html = (MarkupString)"<h1> Test </h1>"; }
原文鏈接:https://www.cnblogs.com/whuanle/p/12862384.html
相關推薦
- 2022-11-10 Android開發之ViewPager實現滑動切換頁面_Android
- 2023-07-04 Linux直接創建SSH無密碼連接
- 2022-09-21 Android?Intent傳遞大量數據出現問題解決_Android
- 2022-06-11 golang實現簡單工廠、方法工廠、抽象工廠三種設計模式_Golang
- 2022-08-06 C語言實現UDP通信_C 語言
- 2023-04-02 linux?top命令基本實戰_linux shell
- 2022-05-25 <C++>搞明白構造函數和析構函數有這一篇就夠了
- 2022-12-05 單步調試?step?into/step?out/step?over?區別說明_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支