小米网站设计,韩国vps,wordpress定义小工具,免费品牌网站制作.简介Blazor的生命周期与React组件的生命周期类似#xff0c;也分为三个阶段#xff1a;初始化阶段、运行中阶段和销毁阶段#xff0c;其相关方法有10个#xff0c;包括设置参数前、初始化、设置参数之后、组件渲染后以及组件的销毁#xff0c;但是这些方法有些是重复的也分为三个阶段初始化阶段、运行中阶段和销毁阶段其相关方法有10个包括设置参数前、初始化、设置参数之后、组件渲染后以及组件的销毁但是这些方法有些是重复的只不过是同步与异步的区别。2.图解首先将结果图呈现代码位于第3部分1997712-20200405180006291-1493915010Blazor生命周期方法主要包括1设置参数前SetParametersAsync2初始化OnInitialized/OnInitializedAsync3设置参数后OnParametersSet/OnParametersSetAsync4组件渲染呈现后OnAfterRender/OnAfterRenderAsync5判断是否渲染组件ShouldRender6组件删除前Dispose7通知组件渲染StateHasChanged在所有生命周期函数中有以下需要注意的点1前5种方法的声明都是virtual除SetParametersAsync为public外其他的都是protected。2OnAfterRender/OnAfterRenderAsync方法有一个bool类型的形参firstRender用于指示是否是第一次渲染即组件初始化时的渲染。3同步方法总是先于异步方法执行。4Dispose函数需要通过使用implements指令实现IDisposable接口来实现。5StateHasChanged无法被重写可以被显示调用以便强制实现组件刷新如果ShouldRender返回true并且Blazor认为需要刷新当组件状态更改时不必显示调用此函数也可导致组件的重新渲染如果ShouldRender返回true因为其已经在ComponentBase内部的处理过程第一次初始化设置参数时、设置参数后和DOM事件处理等中被调用。3.代码示例设置参数时 (SetParametersAsync 设置由组件的父组件在呈现树或路由参数中提供的参数。每次调用 ParameterView 时方法的 参数都包含该组件的SetParametersAsync值集。 通过重写 SetParametersAsync 方法C#代码可以直接与 ParameterView 参数交互。page /set-params-async/{Param?}PageTitleSet Parameters Async/PageTitleh1Set Parameters Async Example/h1pmessage/pcode {private string message Not set;[Parameter]public string? Param { get; set; }public override async Task SetParametersAsync(ParameterView parameters){if (parameters.TryGetValuestring(nameof(Param), out var value)){if (value is null){message The value of Param is null.;}else{message $The value of Param is {value}.;}}await base.SetParametersAsync(parameters);}}组件初始化 (OnInitialized 和 OnInitializedAsync 专门用于在组件实例的整个生命周期内初始化组件。 参数值和参数值更改不应影响在这些方法中执行的初始化。 例如将静态选项加载到下拉列表中该下拉列表在组件的生命周期内不会更改也不依赖于参数值这是在这些生命周期方法之一中执行的操作。 如果参数值或参数值更改会影响组件状态请改为使用 OnParametersSet{Async}。组件在接收 SetParametersAsync 中的初始参数后初始化此时将调用这些方法。如果使用同步父组件初始化则保证父组件初始化在子组件初始化之前完成。 如果使用异步父组件初始化则无法确定父组件和子组件初始化的完成顺序因为它取决于正在运行的初始化代码。对于同步操作重写 OnInitializedpage /on-initPageTitleOn Initialized/PageTitleh1On Initialized Example/h1pmessage/pcode {private string? message;protected override void OnInitialized() message $Initialized at {DateTime.Now};}若要执行异步操作请替代 OnInitializedAsync 并使用 await 运算符protected override async Task OnInitializedAsync(){//await ...await Task.Delay(2000); //2秒之后message $Initialized at {DateTime.Now} after 2 second delay;}如果自定义基类与自定义初始化逻辑一起使用需在基类上调用 OnInitializedAsyncprotected override async Task OnInitializedAsync(){await ...await base.OnInitializedAsync();}设置参数之后 (OnParametersSet 或 OnParametersSetAsync 在以下情况下调用在 OnInitialized 或 OnInitializedAsync 中初始化组件后。当父组件重新呈现并提供以下内容时至少一个参数已更改时的已知或基元不可变类型。复杂类型的参数。 框架无法知道复杂类型参数的值是否在内部发生了改变因此如果存在一个或多个复杂类型的参数框架始终将参数集视为已更改。在组件路由中不能同时对DateTime参数使用datetime路由约束并将该参数设为可选。 因此以下 OnParamsSet 组件使用两个 page 指令来处理具有和没有 URL 中提供的日期段的路由。page /on-params-setpage /on-params-set/{StartDate:datetime}PageTitleOn Parameters Set/PageTitleh1On Parameters Set Example/h1pPass a datetime in the URI of the browsers address bar.For example, add code/1-1-2024/code to the address./ppmessage/pcode {private string? message;[Parameter]public DateTime StartDate { get; set; }protected override void OnParametersSet(){if (StartDate default){StartDate DateTime.Now;message $No start date in URL. Default value applied $(StartDate: {StartDate}).;}else{message $The start date in the URL was used $(StartDate: {StartDate}).;}}}应用参数和属性值时异步操作必须在 OnParametersSetAsync 生命周期事件期间发生protected override async Task OnParametersSetAsync(){await ...}如果自定义基类与自定义初始化逻辑一起使用需在基类上调用 OnParametersSetAsyncprotected override async Task OnParametersSetAsync(){await ...await base.OnParametersSetAsync();}组件呈现之后 (OnAfterRender 和 OnAfterRenderAsync 在组件以交互方式呈现并且 UI 完成更新之后被调用例如元素添加到浏览器 DOM 之后。 此时会填充元素和组件引用。 在此阶段中可使用呈现的内容执行其他初始化步骤例如与呈现的 DOM 元素交互的 JS 互操作调用。这些方法不会在预呈现或静态服务器端渲染静态 SSR期间在服务器上调用因为这些进程未附加到实时浏览器 DOM并且已在 DOM 更新之前完成。对于 OnAfterRenderAsync组件在任何返回 Task 的操作完成后不会自动重渲染以避免无限渲染循环。firstRender 和 OnAfterRender 的 OnAfterRenderAsync 参数在第一次呈现组件实例时设置为 true。可用于确保初始化操作仅执行一次。page /after-renderinject ILoggerAfterRender LoggerPageTitleAfter Render/PageTitleh1After Render Example/h1pbutton onclickHandleClickLog information (and trigger a render)/button/ppStudy logged messages in the console./pcode {protected override void OnAfterRender(bool firstRender) Logger.LogInformation(firstRender {FirstRender}, firstRender);private void HandleClick() Logger.LogInformation(HandleClick called);}加载页面并选择按钮时AfterRender.razor 示例向控制台输出以下内容在渲染后立即进行的异步工作必须在 OnAfterRenderAsync 生命周期事件期间发生protected override async Task OnAfterRenderAsync(bool firstRender){...}如果自定义基类与自定义初始化逻辑一起使用需在基类上调用 OnAfterRenderAsyncprotected override async Task OnAfterRenderAsync(bool firstRender){...await base.OnAfterRenderAsync(firstRender);}基类生命周期方法重写 Blazor 的生命周期方法时无需为 ComponentBase 调用基类生命周期方法。 但在以下情况下组件应调用重写的基类生命周期方法重写 ComponentBase.SetParametersAsync 时通常会调用 await base.SetParametersAsync(parameters);, 因为基类方法会调用其他生命周期方法并以复杂的方式触发渲染。 有关详细信息请参阅设置参数时 (SetParametersAsync) 部分。如果基类方法包含必须执行的逻辑。 库使用者通常在继承基类时调用基类生命周期方法因为库基类通常具有要执行的自定义生命周期逻辑。 如果应用使用某个库中的基类请参阅该库的文档以获取指导。以下示例中调用了 base.OnInitialized(); 以确保会执行基类的 OnInitialized 方法。 如果没有调用BlazorRocksBase2.OnInitialized 不会执行。page /blazor-rocks-2inherits BlazorRocksBase2inject ILoggerBlazorRocks2 LoggerPageTitleBlazor Rocks!/PageTitleh1Blazor Rocks! Example 2/h1pBlazorRocksText/pcode {protected override void OnInitialized(){Logger.LogInformation(Initialization code of BlazorRocks2 executed!);base.OnInitialized();}}using Microsoft.AspNetCore.Components;namespace BlazorAppWasm{public class BlazorRocksBase2: ComponentBase{[Inject]private ILoggerBlazorRocksBase2 Logger { get; set; } default!;public string BlazorRocksText { get; set; } Blazor rocks the browser!;protected override void OnInitialized() Logger.LogInformation(Initialization code of BlazorRocksBase2 executed!);}}2、数据绑定Blazor提供了强大的数据绑定机制主要包括单向绑定和双向绑定两种模式。1. 单向数据绑定单向绑定是指数据从组件流向UI但UI的变化不会自动更新数据源。基本语法!-- 使用 符号进行单向绑定 --p当前值: currentValue/pspan用户名: UserName/spandiv创建时间: CreateTime.ToString(yyyy-MM-dd)/div完整示例!-- OneWayBinding.razor --div classone-way-demoh3单向绑定示例/h3!-- 显示数据但不允许编辑 --div classdisplay-areap计数器: strongcount/strong/pp消息: strongmessage/strong/pp用户信息: stronguser.Name/strong - stronguser.Age/strong岁/p/div!-- 控制按钮 --div classcontrol-areabutton onclickIncrement classbtn btn-primary增加计数/buttonbutton onclickChangeMessage classbtn btn-secondary更改消息/buttonbutton onclickUpdateUser classbtn btn-info更新用户/button/div/divcode {private int count 0;private string message 初始消息;private User user new User { Name 张三, Age 25 };private void Increment(){count;// StateHasChanged(); // 通常不需要手动调用事件处理会自动触发重新渲染}private void ChangeMessage(){message $消息已更新: {DateTime.Now:HH:mm:ss};}private void UpdateUser(){user new User { Name 李四, Age 30 };}class User{public string Name { get; set; } string.Empty;public int Age { get; set; }}}2. 双向数据绑定双向绑定允许数据在组件和UI之间双向流动UI变化自动更新数据源数据源变化自动更新UI。基本语法!-- 使用 bind 指令进行双向绑定 --input bindpropertyName /input bindfieldName /select bindselectedValue.../select完整示例!-- TwoWayBinding.razor --div classtwo-way-demoh3双向绑定示例/h3div classform-grouplabel用户名:/labelinput binduserName classform-control /small显示: userName/small/divdiv classform-grouplabel邮箱:/labelinput bindemail classform-control /small显示: email/small/divdiv classform-grouplabel年龄:/labelinput bindage typenumber classform-control /small显示: age/small/divdiv classform-grouplabel城市:/labelselect bindselectedCity classform-controloption value请选择/optionoption valueBeijing北京/optionoption valueShanghai上海/optionoption valueGuangzhou广州/optionoption valueShenzhen深圳/option/selectsmall选择: selectedCity/small/divdiv classform-grouplabel是否同意协议:/labelinput typecheckbox bindisAgreed /span(isAgreed ? 已同意 : 未同意)/span/div!-- 显示汇总信息 --div classsummaryh4汇总信息:/h4p用户名: userName/pp邮箱: email/pp年龄: age/pp城市: selectedCity/pp同意协议: isAgreed/p/div/divcode {private string userName string.Empty;private string email string.Empty;private int age 0;private string selectedCity string.Empty;private bool isAgreed false;}3. 绑定事件控制3.1 绑定特定事件默认情况下bind 在失去焦点时更新。可以使用 bind:event 指定触发事件!-- 实时绑定输入时立即更新 --div classreal-time-demoh4实时绑定示例/h4input bindsearchText bind:eventoninputplaceholder输入搜索内容... /p实时搜索: searchText/p!-- 对比默认行为 --input bindnormalText placeholder默认绑定失去焦点更新 /p默认绑定: normalText/p/divcode {private string searchText string.Empty;private string normalText string.Empty;}3.2 绑定格式化div classformat-demoh4格式化绑定示例/h4!-- 日期格式化 --input bindstartDate bind:formatyyyy-MM-dd typedate /p选择的日期: startDate.ToString(yyyy年MM月dd日)/p!-- 数字格式化 --input bindprice bind:formatF2 typenumber step0.01 /p价格: price.ToString(C)/p/divcode {private DateTime startDate DateTime.Today;private decimal price 0.00m;}4. 自定义组件双向绑定在自定义组件中实现双向绑定子组件!-- CustomInput.razor --div classcustom-inputlabelLabel/labelinputvalueValueoninputHandleInputclassform-control AdditionalClassplaceholderPlaceholder /if (!string.IsNullOrEmpty(ValidationMessage)){div classtext-dangerValidationMessage/div}/divcode {[Parameter]public string Value { get; set; } string.Empty;[Parameter]public EventCallbackstring ValueChanged { get; set; }[Parameter]public string Label { get; set; } string.Empty;[Parameter]public string Placeholder { get; set; } string.Empty;[Parameter]public string AdditionalClass { get; set; } string.Empty;[Parameter]public string ValidationMessage { get; set; } string.Empty;private async Task HandleInput(ChangeEventArgs e){Value e.Value?.ToString() ?? string.Empty;await ValueChanged.InvokeAsync(Value);}}父组件使用!-- ParentComponent.razor --div classparent-demoh3自定义组件双向绑定/h3CustomInputbind-ValueuserNameLabel用户名Placeholder请输入用户名 /CustomInputbind-ValueemailLabel邮箱Placeholder请输入邮箱地址ValidationMessage(IsValidEmail ? : 邮箱格式不正确) /div classresultp用户名: userName/pp邮箱: email/p/div/divcode {private string userName string.Empty;private string email string.Empty;private bool IsValidEmail email.Contains() email.Contains(.);}5.复杂对象绑定!-- ComplexObjectBinding.razor --div classcomplex-bindingh3复杂对象绑定/h3div classform-sectionh4用户信息/h4div classform-grouplabel姓名:/labelinput bindcurrentUser.Name classform-control //divdiv classform-grouplabel年龄:/labelinput bindcurrentUser.Age typenumber classform-control //divdiv classform-grouplabel地址:/labelinput bindcurrentUser.Address.Street classform-control placeholder街道 /input bindcurrentUser.Address.City classform-control placeholder城市 //div/divdiv classdisplay-sectionh4当前用户信息:/h4preuserInfoJson/pre/divbutton onclickResetUser classbtn btn-warning重置用户/buttonbutton onclickCreateNewUser classbtn btn-success创建新用户/button/divcode {private User currentUser new User();private string userInfoJson System.Text.Json.JsonSerializer.Serialize(currentUser, new System.Text.Json.JsonSerializerOptions{WriteIndented true});private void ResetUser(){currentUser new User();}private void CreateNewUser(){currentUser new User{Name 新用户,Age 18,Address new Address { Street 新建街道, City 新建城市 }};}class User{public string Name { get; set; } string.Empty;public int Age { get; set; }public Address Address { get; set; } new Address();}class Address{public string Street { get; set; } string.Empty;public string City { get; set; } string.Empty;}}6.绑定模式对比绑定类型语法更新时机适用场景单向绑定property数据源变化时显示数据、计算属性双向绑定bindproperty失去焦点时表单输入、用户交互实时双向bindproperty bind:eventoninput输入时实时更新搜索框、实时验证自定义绑定bind-Valueproperty自定义事件触发自定义表单组件3、事件处理1. 基本事件处理1.1 单击事件!-- ClickEvents.razor --div classclick-demoh3单击事件示例/h3!-- 基本点击事件 --button onclickHandleClick classbtn btn-primary点击我/button!-- 带参数的事件处理 --div classbutton-groupbutton onclick() HandleButtonClick(1) classbtn btn-secondary按钮 1/buttonbutton onclick() HandleButtonClick(2) classbtn btn-secondary按钮 2/buttonbutton onclick() HandleButtonClick(3) classbtn btn-secondary按钮 3/button/div!-- 显示点击结果 --div classresultp最后点击的按钮: lastClickedButton/pp点击次数: clickCount/p/div/divcode {private int lastClickedButton 0;private int clickCount 0;private void HandleClick(){clickCount;Console.WriteLine(按钮被点击了);}private void HandleButtonClick(int buttonNumber){lastClickedButton buttonNumber;clickCount;StateHasChanged();}}1.2 异步事件处理!-- AsyncEvents.razor --div classasync-demoh3异步事件处理/h3button onclickHandleAsyncClick classbtn btn-primary disabledisLoadingif (isLoading){span加载中.../span}else{span模拟异步操作/span}/buttondiv classresultp操作结果: operationResult/pp耗时: elapsedTime 毫秒/p/div/divcode {private bool isLoading false;private string operationResult string.Empty;private long elapsedTime 0;private async Task HandleAsyncClick(){isLoading true;operationResult 操作开始...;var stopwatch System.Diagnostics.Stopwatch.StartNew();// 模拟异步操作await Task.Delay(2000);stopwatch.Stop();elapsedTime stopwatch.ElapsedMilliseconds;operationResult $操作完成数据已保存。;isLoading false;StateHasChanged();}}2. 表单事件处理2.1 输入事件!-- FormEvents.razor --div classform-eventsh3表单事件处理/h3div classform-grouplabel输入文本:/labelinput oninputHandleInputonchangeHandleChangeclassform-controlplaceholder输入内容... /small实时输入: inputValue | 变化事件: changeValue/small/divdiv classform-grouplabel选择选项:/labelselect onchangeHandleSelectChange classform-controloption value请选择/optionoption valueoption1选项一/optionoption valueoption2选项二/optionoption valueoption3选项三/option/selectsmall选择的值: selectedValue/small/divdiv classform-grouplabelinput typecheckbox onchangeHandleCheckboxChange /同意条款/labelsmall状态: (isChecked ? 已选中 : 未选中)/small/div!-- 表单提交 --form onsubmitHandleSubmit onvalidSubmitHandleValidSubmitdiv classform-grouplabel用户名:/labelinput binduser.Username classform-control required //divdiv classform-grouplabel邮箱:/labelinput binduser.Email typeemail classform-control required //divbutton typesubmit classbtn btn-success提交表单/button/formdiv classform-resulth4表单数据:/h4preSystem.Text.Json.JsonSerializer.Serialize(user, new System.Text.Json.JsonSerializerOptions { WriteIndented true })/prep提交状态: submitStatus/p/div/divcode {private string inputValue string.Empty;private string changeValue string.Empty;private string selectedValue string.Empty;private bool isChecked false;private string submitStatus 未提交;private User user new User();private void HandleInput(ChangeEventArgs e){inputValue e.Value?.ToString() ?? string.Empty;}private void HandleChange(ChangeEventArgs e){changeValue e.Value?.ToString() ?? string.Empty;}private void HandleSelectChange(ChangeEventArgs e){selectedValue e.Value?.ToString() ?? string.Empty;}private void HandleCheckboxChange(ChangeEventArgs e){isChecked (bool)(e.Value ?? false);}private void HandleSubmit(){submitStatus 表单提交可能有验证错误;}private void HandleValidSubmit(){submitStatus $表单验证通过数据已保存 - {DateTime.Now:HH:mm:ss};// 这里可以调用API保存数据}class User{public string Username { get; set; } string.Empty;public string Email { get; set; } string.Empty;}}3. 鼠标和键盘事件3.1 鼠标事件!-- MouseEvents.razor --div classmouse-eventsh3鼠标事件/h3div classinteractive-areaonmousedownHandleMouseDownonmouseupHandleMouseUponmousemoveHandleMouseMoveonmouseoverHandleMouseOveronmouseoutHandleMouseOutonclickHandleAreaClickondblclickHandleDoubleClickstylewidth: 300px; height: 200px; border: 2px solid #007bff; padding: 20px; margin: 10px 0;鼠标交互区域/divdiv classevent-logh4事件日志:/h4ulforeach (var log in eventLogs.TakeLast(10).Reverse()){lilog/li}/ul/divdiv classmouse-infop鼠标位置: (mouseX, mouseY)/pp按钮状态: (isMouseDown ? 按下 : 释放)/pp悬停状态: (isMouseOver ? 在区域内 : 在区域外)/p/div/divcode {private double mouseX 0;private double mouseY 0;private bool isMouseDown false;private bool isMouseOver false;private Liststring eventLogs new Liststring();private void LogEvent(string eventName){eventLogs.Add(${DateTime.Now:HH:mm:ss.fff} - {eventName});StateHasChanged();}private void HandleMouseDown(MouseEventArgs e){isMouseDown true;LogEvent($MouseDown - 按钮: {e.Button}, 位置: ({e.ClientX}, {e.ClientY}));}private void HandleMouseUp(MouseEventArgs e){isMouseDown false;LogEvent($MouseUp - 按钮: {e.Button}, 位置: ({e.ClientX}, {e.ClientY}));}private void HandleMouseMove(MouseEventArgs e){mouseX e.ClientX;mouseY e.ClientY;// 注意频繁触发生产环境需要节流// LogEvent($MouseMove - 位置: ({e.ClientX}, {e.ClientY}));}private void HandleMouseOver(MouseEventArgs e){isMouseOver true;LogEvent(MouseOver);}private void HandleMouseOut(MouseEventArgs e){isMouseOver false;LogEvent(MouseOut);}private void HandleAreaClick(MouseEventArgs e){LogEvent($Click - 按钮: {e.Button});}private void HandleDoubleClick(MouseEventArgs e){LogEvent($DoubleClick - 按钮: {e.Button});}}3.2 键盘事件!-- KeyboardEvents.razor --div classkeyboard-eventsh3键盘事件/h3div classinput-areainput onkeydownHandleKeyDownonkeyupHandleKeyUponkeypressHandleKeyPressclassform-controlplaceholder在这里输入并观察键盘事件... //divdiv classevent-logh4键盘事件日志:/h4ulforeach (var log in keyEventLogs.TakeLast(10).Reverse()){lilog/li}/ul/divdiv classkey-infop最后按下的键: lastKey/ppCtrl 按下: (isCtrlPressed ? 是 : 否)/ppShift 按下: (isShiftPressed ? 是 : 否)/ppAlt 按下: (isAltPressed ? 是 : 否)/p/div/divcode {private string lastKey 无;private bool isCtrlPressed false;private bool isShiftPressed false;private bool isAltPressed false;private Liststring keyEventLogs new Liststring();private void LogKeyEvent(string eventName, KeyboardEventArgs e){var log ${DateTime.Now:HH:mm:ss.fff} - {eventName}: Key{e.Key}, Code{e.Code};if (e.CtrlKey) log [Ctrl];if (e.ShiftKey) log [Shift];if (e.AltKey) log [Alt];keyEventLogs.Add(log);StateHasChanged();}private void HandleKeyDown(KeyboardEventArgs e){lastKey e.Key;isCtrlPressed e.CtrlKey;isShiftPressed e.ShiftKey;isAltPressed e.AltKey;LogKeyEvent(KeyDown, e);// 快捷键处理示例if (e.CtrlKey e.Key s){e.PreventDefault(); // 阻止浏览器默认保存行为LogKeyEvent(快捷键: CtrlS, e);}}private void HandleKeyUp(KeyboardEventArgs e){isCtrlPressed e.CtrlKey;isShiftPressed e.ShiftKey;isAltPressed e.AltKey;LogKeyEvent(KeyUp, e);}private void HandleKeyPress(KeyboardEventArgs e){LogKeyEvent(KeyPress, e);}}4. 焦点和剪贴板事件!-- FocusClipboardEvents.razor --div classfocus-clipboardh3焦点和剪贴板事件/h3div classform-grouplabel焦点测试输入框:/labelinput onfocusHandleFocusonblurHandleBlurclassform-controlplaceholder点击获取焦点点击别处失去焦点 //divdiv classform-grouplabel复制粘贴测试:/labeltextarea oncopyHandleCopyoncutHandleCutonpasteHandlePasteclassform-controlrows3placeholder在这里测试复制、剪切、粘贴操作这是一些测试文本/textarea/divdiv classevent-logh4事件状态:/h4p焦点状态: span class(hasFocus ? text-success : text-danger)(hasFocus ? 有焦点 : 无焦点)/span/pp最后操作: lastOperation/pp剪贴板内容: clipboardContent/p/div/divcode {private bool hasFocus false;private string lastOperation 无;private string clipboardContent 无;private void HandleFocus(FocusEventArgs e){hasFocus true;lastOperation 获得焦点;StateHasChanged();}private void HandleBlur(FocusEventArgs e){hasFocus false;lastOperation 失去焦点;StateHasChanged();}private void HandleCopy(ClipboardEventArgs e){lastOperation 复制操作;clipboardContent 复制的内容无法直接获取安全限制;StateHasChanged();}private void HandleCut(ClipboardEventArgs e){lastOperation 剪切操作;clipboardContent 剪切的内容无法直接获取安全限制;StateHasChanged();}private void HandlePaste(ClipboardEventArgs e){lastOperation 粘贴操作;clipboardContent 粘贴的内容无法直接获取安全限制;StateHasChanged();}}5. 自定义事件处理5.1 事件参数封装!-- CustomEventHandling.razor --div classcustom-eventsh3自定义事件处理/h3!-- 事件冒泡和阻止默认行为 --div onclickHandleParentClick stylepadding: 20px; border: 2px solid red;p父级区域点击会触发/pbutton onclickHandleChildClickonclick:stopPropagationclassbtn btn-primary子按钮点击不会冒泡/buttonbutton onclickHandleChildClickWithPreventonclick:preventDefaultclassbtn btn-secondary阻止默认行为的按钮/button/div!-- 自定义事件处理逻辑 --div classcustom-actionsh4自定义操作:/h4button onclickHandleCustomAction1 classbtn btn-info操作1/buttonbutton onclickHandleCustomAction2 classbtn btn-info操作2/buttonbutton onclickasync () await HandleCustomAsyncAction() classbtn btn-info异步操作/button/divdiv classaction-logh4操作日志:/h4ulforeach (var log in actionLogs.TakeLast(5).Reverse()){lilog/li}/ul/div/divcode {private Liststring actionLogs new Liststring();private void LogAction(string action){actionLogs.Add(${DateTime.Now:HH:mm:ss} - {action});StateHasChanged();}private void HandleParentClick(){LogAction(父级区域被点击);}private void HandleChildClick(){LogAction(子按钮被点击事件不会冒泡);}private void HandleChildClickWithPrevent(){LogAction(阻止默认行为的按钮被点击);}private void HandleCustomAction1(){LogAction(执行自定义操作1);// 自定义业务逻辑}private void HandleCustomAction2(MouseEventArgs e){LogAction($执行自定义操作2 - 点击位置: ({e.ClientX}, {e.ClientY}));// 自定义业务逻辑}private async Task HandleCustomAsyncAction(){LogAction(开始异步操作);await Task.Delay(1000);LogAction(异步操作完成);}}6. 事件处理最佳实践6.1 性能优化!-- OptimizedEvents.razor --div classoptimized-eventsh3事件处理性能优化/h3!-- 避免内联Lambda表达式可能引起不必要的重渲染 --foreach (var item in items){div classitem keyitem.Idspanitem.Name/span!-- 好的做法使用方法引用 --button onclick() DeleteItem(item.Id) classbtn btn-sm btn-danger删除/button/div}!-- 大量事件考虑使用事件委托 --div classlarge-listforeach (var item in largeList){div classlist-item data-iditem.Id data-nameitem.Name onclick(e) HandleListItemClick(e, item.Id)item.Name/div}/divdiv classaction-logh4操作日志:/h4ulforeach (var log in actionLogs.TakeLast(5).Reverse()){lilog/li}/ul/div/divcode {private ListItem items new ListItem{new Item { Id 1, Name 项目1 },new Item { Id 2, Name 项目2 },new Item { Id 3, Name 项目3 }};private ListItem largeList Enumerable.Range(1, 100).Select(i new Item { Id i, Name $项目{i} }).ToList();private Liststring actionLogs new Liststring();private void DeleteItem(int id){items.RemoveAll(i i.Id id);LogAction($删除了项目 {id});}private void HandleListItemClick(MouseEventArgs e, int itemId){// 通过参数 itemId 就知道是哪个按钮被点击了Console.WriteLine($Clicked item ID: {itemId});}// 添加 LogAction 方法private void LogAction(string action){actionLogs.Add(${DateTime.Now:HH:mm:ss} - {action});StateHasChanged();}class Item{public int Id { get; set; }public string Name { get; set; } string.Empty;}}7. 常用事件总结事件类型指令事件参数说明点击事件onclickMouseEventArgs鼠标点击双击事件ondblclickMouseEventArgs鼠标双击鼠标移动onmousemoveMouseEventArgs鼠标移动鼠标按下onmousedownMouseEventArgs鼠标按下鼠标释放onmouseupMouseEventArgs鼠标释放键盘按下onkeydownKeyboardEventArgs键盘按下键盘释放onkeyupKeyboardEventArgs键盘释放输入事件oninputChangeEventArgs输入时触发变化事件onchangeChangeEventArgs值变化时触发获得焦点onfocusFocusEventArgs元素获得焦点失去焦点onblurFocusEventArgs元素失去焦点表单提交onsubmitEventArgs表单提交4、组件参数和级联参数1. 组件参数(Parameter)参数主要用来在各组件之间传递值在初始项目的SurveyPrompt组件中就包含了一个参数:[Parameter]public string Title { get; set; }通过用Parameter修饰符来修饰就可以将指定的属性注意要是public的声明为参数使用也很简单SurveyPrompt Title这里是参数的值 /2. CaptureUnmatchedValues是 Blazor 中一个非常有用的特性它允许组件捕获所有未匹配到组件参数的额外属性。基本概念当你在组件上设置了属性但这些属性没有对应的 时可以捕获这些未匹配的属性而且修饰的属性必须要是字典类型IDictionarystring,object。基本用法!-- MyComponent.razor --div attributesAdditionalAttributes组件内容/divcode {[Parameter(CaptureUnmatchedValues true)]public Dictionarystring, object AdditionalAttributes { get; set; } new Dictionarystring, object();}!-- MyComponent.razor --div attributesAdditionalAttributes组件内容/divcode {[Parameter(CaptureUnmatchedValues true)]public Dictionarystring, object AdditionalAttributes { get; set; } new Dictionarystring, object();}!-- MyComponent.razor --div attributesAdditionalAttributes组件内容/divcode {[Parameter(CaptureUnmatchedValues true)]public Dictionarystring, object AdditionalAttributes { get; set; } new Dictionarystring, object();}!-- MyComponent.razor --div attributesAdditionalAttributes组件内容/divcode {[Parameter(CaptureUnmatchedValues true)]public Dictionarystring, object AdditionalAttributes { get; set; } new Dictionarystring, object();}使用场景示例1. 创建可复用的按钮组件!-- MyButton.razor --button attributesAdditionalAttributes classbtn ClassChildContent/buttoncode {[Parameter]public string Class { get; set; } string.Empty;[Parameter]public RenderFragment? ChildContent { get; set; }[Parameter(CaptureUnmatchedValues true)]public Dictionarystring, object AdditionalAttributes { get; set; } new Dictionarystring, object();}!-- MyButton.razor --button attributesAdditionalAttributes classbtn ClassChildContent/buttoncode {[Parameter]public string Class { get; set; } string.Empty;[Parameter]public RenderFragment? ChildContent { get; set; }[Parameter(CaptureUnmatchedValues true)]public Dictionarystring, object AdditionalAttributes { get; set; } new Dictionarystring, object();}!-- MyButton.razor --button attributesAdditionalAttributes classbtn ClassChildContent/buttoncode {[Parameter]public string Class { get; set; } string.Empty;[Parameter]public RenderFragment? ChildContent { get; set; }[Parameter(CaptureUnmatchedValues true)]public Dictionarystring, object AdditionalAttributes { get; set; } new Dictionarystring, object();}!-- MyButton.razor --button attributesAdditionalAttributes classbtn ClassChildContent/buttoncode {[Parameter]public string Class { get; set; } string.Empty;[Parameter]public RenderFragment? ChildContent { get; set; }[Parameter(CaptureUnmatchedValues true)]public Dictionarystring, object AdditionalAttributes { get; set; } new Dictionarystring, object();}使用方式MyButton classbtn-primaryidsubmit-btnonclickconsole.log(clicked me)data-customvalue点击我/MyButtonMyButton classbtn-primaryidsubmit-btnonclickconsole.log(clicked me)data-customvalue点击我/MyButtonMyButton classbtn-primaryidsubmit-btnonclickconsole.log(clicked me)data-customvalue点击我/MyButtonMyButton classbtn-primaryidsubmit-btnonclickconsole.log(clicked me)data-customvalue点击我/MyButton2.包装第三方组件!-- WrapperComponent.razor --ThirdPartyComponent attributesAdditionalAttributesSpecificParameterSpecificValue /code {[Parameter]public string SpecificValue { get; set; } string.Empty;[Parameter(CaptureUnmatchedValues true)]public Dictionarystring, object AdditionalAttributes { get; set; } new Dictionarystring, object();}!-- WrapperComponent.razor --ThirdPartyComponent attributesAdditionalAttributesSpecificParameterSpecificValue /code {[Parameter]public string SpecificValue { get; set; } string.Empty;[Parameter(CaptureUnmatchedValues true)]public Dictionarystring, object AdditionalAttributes { get; set; } new Dictionarystring, object();}!-- WrapperComponent.razor --ThirdPartyComponent attributesAdditionalAttributesSpecificParameterSpecificValue /code {[Parameter]public string SpecificValue { get; set; } string.Empty;[Parameter(CaptureUnmatchedValues true)]