【问题标题】:Blazor button, use parent component @onclickBlazor 按钮,使用父组件@onclick
【发布时间】:2020-10-08 10:16:11
【问题描述】:

是否可以使用父组件方法@onclick,还是我需要从子组件调用它?

假设我想调用父方法 Foo()。

家长

@page "/"

// Custom component button
<Button Text="Some text" @onclick="Foo" Apperance="@Style.secondary" /> 


@code {
    async Task Foo() 
    {
        // ...
    }
}

儿童

<button class="btn @_cssClass"><span>@Text</span></button>

@code {
    public enum Style
    {
        primary,
        secondary,
        tertiary,
        danger
    }

    [Parameter]
    public string Text { get; set; }
    [Parameter]
    public Style Apperance { get; set; }
    private string _cssClass { get; set; }

    protected override void OnInitialized()
    {
        _cssClass = Apperance switch
        {
            Style.secondary => "btn--secondary",
            Style.tertiary => "btn--tertiary",
            Style.danger => "btn--danger",
            _ => "btn--primary"
        };
    }
}

我收到此错误:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      未处理的异常呈现组件:“Tidrapport.Client.Components.Button”类型的对象没有与名称“onclick”匹配的属性。
System.InvalidOperationException:“Tidrapport.Client.Components.Button”类型的对象没有与名称“onclick”匹配的属性。

我确实想要一个子按钮组件,当它被点击时(在父组件中呈现) - 我想在父组件中调用一个方法。

【问题讨论】:

    标签: blazor


    【解决方案1】:

    你不能那样使用@onclick指令...这个指令与Html元素一起使用,指示编译器为点击事件创建事件处理程序,例如:

    <button type="button" @onclick="ClickEventHandler">Click me</button>
    
    @code{
       private void ClickEventHandler()
       {
          Cosole.WriteLine("Hello Blazor");
        }
    }
    

    然而,当你绑定组件时,你应该这样做:

    ChildComponent.razor

    <input type="text" @bind="Text" @bind:event="oninput" />
    
    @code {
            private string text { get; set; }
    
            [Parameter]
            public string Text
            {
                get { return text; }
                set
                {
                    if (text != value) {
                        text = value;
                        if (TextChanged.HasDelegate)
                        {
                            TextChanged.InvokeAsync(value);
                        }
                    }
                }
            }
    
            [Parameter]
            public EventCallback<string> TextChanged { get; set; }
        }
    

    如你所见,我定义了一个名为Text的参数Property...为了创建双向数据绑定,你还应该定义一个EventCallback 'delegate',其作用是更新父级中的绑定对象零件。因此,您将在父组件中编写代码:

    <ChildComponent @bind-Text="Text" />
    

    请注意,EventCallback 委托的名称由 Text 单词加上 Changed 单词组成。

    @bind-Text 指令将子组件中定义的 Text 属性绑定到父组件中定义的 Text 属性(见下方代码)。

    因此规则是 @bind- 加上子组件中的属性名称,例如 Value 转到 @bind-Value 并且其值应该是属性名称,例如 MyValue 和因此:@bind-Value="MyValue"

    但是,在子组件中,您应该定义一个名为 Value 的参数属性和一个名为 ValueChangedEventCallback...

    这是一个完整的工作代码 sn-p,演示了父组件与其子组件之间的双向数据绑定:

    ParentComponent.razor

    @page "/ParentComponent"
    
    <h1>Parent Component</h1>
    
    <input type="text" @bind="Text" @bind:event="oninput" />
    <p></p>
    
    <ChildComponent @bind-Text="Text" />
    
    
    @code {
        [Parameter]
        public string Text { get; set; } = "Hello Blazor";
    }
    

    希望这行得通...

    【讨论】:

    • 谢谢,但这是与字符串的双向数据绑定,这不是我所追求的。也许我有点不清楚。所以,我确实想要一个子按钮组件,当它被点击时 - 我想调用父组件中的一个方法。
    【解决方案2】:

    所以,我确实想要一个子按钮组件,当它被点击时 - 我想在父组件中调用一个方法。

    您的 ChildComponent 应该如下所示:

    <button type="button" @onclick="CallMethodParent">Call a method on parent component</button>
    
    
        @code {
        
            [Parameter]
            public EventCallback<string> ParentMethod { get; set; }
        
            private async Task CallMethodParent()
            {
                if(ParentMethod.HasDelegate)
                {
                  await  ParentMethod.InvokeAsync("A message from child component...");
                }
            }
        
        }
    

    用法

    <p>@message</p>
    
    <ChildComponent ParentMethod="ParentMethod"/>
    
    @code{
        private string message;
    
        private void ParentMethod(string message)
        {
            this.message = message;
        }
    
    }
    

    注意:这里的主要内容是您应该在子组件中定义一个参数EventCallback属性,该属性存储在父组件中定义的方法。

    希望这会有所帮助...

    【讨论】:

    • 再次感谢评论,找到解决方案后才看到。
    【解决方案3】:

    所以我找到了我的问题的答案,你设计了一个 EventCallbackdocs 中找到。

    所以对我来说,它看起来像这样。

    家长

    @page "/"
    
    // Custom component button
    <Button Text="Some text" OnClickCallback="@Foo" Apperance="@Style.secondary" /> 
    
    @code {
        async Task Foo() 
        {
            // ...
        }
    }
    

    儿童

    <button class="btn @_cssClass" @onclick="OnClickCallback"><span>@Text</span></button>
    
    @code {
        public enum Style
        {
            primary,
            secondary,
            tertiary,
            danger
        }
    
        [Parameter]
        public string Text { get; set; }
        [Parameter]
        public Style Apperance { get; set; }
        private string _cssClass { get; set; }
        [Parameter]
        public EventCallback OnClickCallback { get; set; } // this is where to you pass the parent function to be executed as a callback
    
        protected override void OnInitialized()
        {
            _cssClass = Apperance switch
            {
                Style.secondary => "btn--secondary",
                Style.tertiary => "btn--tertiary",
                Style.danger => "btn--danger",
                _ => ""
            };
        }
    }
    

    所以onclick事件绑定到你在子组件中设计的事件处理器。如果您想使用参数,它可以是 T 类型,更多信息请参阅文档。

    【讨论】:

      【解决方案4】:

      您可以使用attribute splatting,它允许您继续使用 Razor 的@onclick 属性,而不是声明回调。

      只需将以下内容添加到您的子类中:

      1. 捕获不匹配值的参数
      2. 子元素上的@attributes Razor 属性。

      例如,有一个如下所示的Button.razor 文件:

      <button class="btn" @attributes="AdditionalAttributes">@Text</button>
      
      @code {
      
          [Parameter]
          public string Text { get; set; }
      
          [Parameter(CaptureUnmatchedValues = true)]
          public Dictionary<string, object> AdditionalAttributes { get; set; }
      }
      

      那么你可以这样称呼它:

      <Button Text="Some text" @onclick="Foo" />
      

      请注意,这将应用所有不匹配的属性,而不仅仅是@onclick,并将覆盖之前声明的所有属性。在某些情况下这可能是不可取的,在这种情况下,您可以使用 EventCallback

      【讨论】:

        猜你喜欢
        • 2022-10-03
        • 2020-09-28
        • 1970-01-01
        • 2020-09-29
        • 2015-06-25
        • 2019-09-29
        • 2018-01-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多