• Blazor带我重玩前端(六)


    本文主要讨论Blazor事件内容,由于blazor事件部分很多,所以会分成上下两篇,本文为第二篇。

    双向绑定

    概述

    8

    如图所示

    • 当点击单项绑定的时候,MyOnewayComponent里的属性值会发生变化,这种变化是单项的,仅仅只是本地副本的值的变化,并不会引发父页面的值发生变化。但当点击父页面的Click Me的时候,会修改MyOnewayComponent的属性值会被修改。所以单项绑定强调的是占位,以达到动态输出的目的。
    • 当点击双向绑定的时候,三个值会同步发生变化。即便点击父页面的Click Me,也不会覆盖掉MyTwoWayComponent的属性值,这说明父页面和MyTwoWayComponent页面的值发生了双向绑定,会导致数据同步变化。
    • 双向绑定,绑定的是Blazor组件和dom元素,就像是宏指令一样。也就是说,当该组件首次运行时,输入框的值来自于CurrentValue属性,当用户输入新的值后,CurrentValue也将会被设置成新的值。

    示例

    双向绑定有一个重要特征就是使用@bind-进行数据绑定,之前我创建了两个组件,我们来看一下这两个组件的源代码:MyOnewayComponent:

       1:  <div>
       2:      MyComponent CounterValue is @CounterValue
       3:  </div>
       4:  <button @onclick=UpdateCounterValue>Update</button>
       5:  @code {
       6:   
       7:      [Parameter]
       8:      public int CounterValue { get; set; }
       9:   
      10:      void UpdateCounterValue()
      11:      {
      12:          CounterValue++;
      13:      }
      14:  }

    MyTwoWayComponent:

         1:  <div>
         2:      MyComponent CounterValue is @CounterValue
         3:  </div>
         4:  <button @onclick=UpdateCounterValue>Update</button>
         5:  @code {
         6:   
         7:      [Parameter]
         8:      public int CounterValue { get; set; }
         9:   
        10:      [Parameter]
        11:      public EventCallback<int> CounterValueChanged { get; set; }
        12:   
        13:      async Task UpdateCounterValue()
        14:      {
        15:          CounterValue++;
        16:          await CounterValueChanged.InvokeAsync(CounterValue);
        17:      }
        18:  }

      以上代码可以看到有明显的不同,MyTwoWayComponent包含一个EventCallback类型的属性,其命名是CounterValueChanged,看起来像是属性值后缀Changed,其调用方法也变成了async Task,该方法表明,当CounterValue发生变化的时候,会通过CounterValueChanged来通知事件源页面该值发生了变化。额外尝试一下,如果我们直接使用MyOnewayComponent 来演示双向绑定,会发生什么,我们使用如下代码运行一下看看:

         1:  <MyOnewayComponent @bind-CounterValue="@currentCount" />

      运行后,发现报错了,错误信息是:Unhandled exception rendering component: Object of type 'BlazorApp.Client.Pages.MyOnewayComponent' does not have a property matching the name 'CounterValueChanged'。由此可见,我们的命名规则是强制的,其必须是所绑定EventCallBack的属性名后缀Changed。

      BuildTree源码

         1:  #pragma warning disable 1998
         2:  protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
         3:  {
         4:      __builder.AddContent(8, "Click me");
         5:      __builder.CloseElement();
         6:      __builder.AddMarkupContent(9, "
      <br>
      <br>
      
      ");
         7:      __builder.OpenComponent<BlazorApp.Client.Pages.MyOnewayComponent>(10);
         8:      __builder.AddAttribute(11, "CounterValue", Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<System.Int32>(
         9:  #nullable restore
        10:                                  currentCount
        11:   
        12:  #line default
        13:  #line hidden
        14:  #nullable disable
        15:      ));
        16:      __builder.AddAttribute(12, "CounterValueChanged", Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this, __value => currentCount = __value, currentCount));
        17:      __builder.CloseComponent();
        18:  }
      • 8-15行是单项绑定的内容
      • 16-18行是双向绑定的内容

        级联值和参数

        概述

        级联值和参数是一种将值从组件传递到其所有子组件的方法,在Blazor中,采用CascadingValue来实现,子组件通过声明同一类型的属性(用[CascadingParameter]属性修饰)来收集并赋值。当级联值发生更新的时候,这种更新将传递到所有的子组件,同时这组件将会自动调用StateHasChanged 。一般情况下,我们的CascadingValue中可能会需要传递多个值的变化,那么这种变化是如何进行的呢。是通过两种方式,一种是类型推导,一种是命名传值。

        类型推导

        我创建了两个组件,分别是FirstComponent,SecondComponent。FirstComponent源码如下:

           1:  <CascadingValue Value="@CascadingIndex">
           2:      <CascadingValue Value="@CascadingName">
           3:          <SecondComponent></SecondComponent>
           4:      </CascadingValue>
           5:  </CascadingValue>
           6:  @code {
           7:  int CascadingIndex = 10000;
           8:   
           9:  string CascadingName = "FirstComponent";
          10:  }

        SecondComponent源码如下:

           1:   
           2:  <h3>SecondComponent</h3>
           3:  <p>
           4:      CascadingValue Is <strong>@SecondValue</strong>
           5:  </p>
           6:  @code {
           7:      [CascadingParameter] int SecondValue { get; set; }
           8:  }

        传值的过程中,我们只有一个int类型的属性,所以该值会显示10000,如下图所示:

        1

        如果我们修改一下FirstComponent的源码,将其中的string类型的属性删除掉,同时增加一个新的int类型的属性,如下源码所示:

           1:  <CascadingValue Value="@CascadingIndex">
           2:      <CascadingValue Value="@Total">
           3:          <SecondComponent></SecondComponent>
           4:      </CascadingValue>
           5:  </CascadingValue>
           6:   
           7:  @code {
           8:  int CascadingIndex { get; set; } = 10000;
           9:   
          10:  int Total{ get; set; } = 2;
          11:  }

        运行结果如下:

        2

        由此可见,当子组件遇到多个相同类型的属性的时候,会选择离子组件最近的属性的值并传递到自己的属性中去。

        命名传值

        命名赋值就很单纯了,主要考虑绑定正确的名称就行。修改后FirstComponent的源码如下,需要指定Name:

           1:  <CascadingValue Value="@CascadingIndex" Name="CascadingIndex">
           2:      <CascadingValue Value="@Total" Name="Total">
           3:          <SecondComponent></SecondComponent>
           4:      </CascadingValue>
           5:  </CascadingValue>
           6:   
           7:  @code {
           8:      int CascadingIndex{ get; set; } = 10000;
           9:   
          10:      int Total{ get; set; } = 2;
          11:  }

        SecondComponent源码如下,可以指定名称已接收值的传递

           1:  <h3>SecondComponent</h3>
           2:  <p>
           3:      CascadingValue Is <strong>@SecondValue</strong>
           4:  </p>
           5:  @code {
           6:      [CascadingParameter(Name = "CascadingIndex")] int SecondValue { get; set; }
           7:  }

        运行后的结果如下,值又变回了一万

        3

        有朋友可能会想,我不想设置SecondComponent中CascadingParameter的Name值,但是我可以设置成FirstComponent中某个已经绑定的Name的名称。如下所示:

        FirstComponent源码不变,SecondComponent源码如下:

           1:  <h3>SecondComponent</h3>
           2:  <p>
           3:      CascadingValue Is <strong>@Total</strong>
           4:  </p>
           5:  @code {
           6:      [CascadingParameter] int Total { get; set; }
           7:  }

        运行结果如下所示:

        4

        由此可见,不设置子组件中CascadingParameter的Name值,是无法接收传递的值的。

        性能问题

        默认情况下,Blazor会持续监控级联值的变化,并将其传递到所有子组件中,这将会占用一定的资源,并可能导致性能问题。

        如果我们可以确定,我们的级联值不会发生变化,可以设置CascadingValue中参数IsFixed的值为true,这样的Blazor就不会监控级联值的变化了。

           1:  <CascadingValue Value="@CascadingIndex" IsFixed="true">
           2:      <SecondComponent></SecondComponent>
           3:  </CascadingValue>
      • 相关阅读:
        [BUGCASE]CI框架的post方法对url做了防xss攻击的处理引发的文件编码错误
        [BUGCASE]Webpack打包报JavaScript堆内存泄漏的错误
        [BUGCASE]前端码案概述
        实现复杂状态机的一种思路
        日期选择组件(DatePicker)的实现
        前端开发的积木理论——像搭积木一样做前端开发
        GitHub 使用
        数组循环常用几种方法
        react 如何引入图片, 背景图片, 盒子上下左右居中
        react select案例
      • 原文地址:https://www.cnblogs.com/edison0621/p/13599106.html
      Copyright © 2020-2023  润新知