【问题标题】:C# Blazor: How to prevent specific key on input like in JS with e.preventDefault()?C# Blazor:如何使用 e.preventDefault() 防止在 JS 中输入特定键?
【发布时间】:2020-02-22 01:29:55
【问题描述】:

这个问题看起来很简单,但是我还没有找到任何解决方案。 我有一个带有 onkeydown 事件的 Blazor 输入:

<input @onkeydown="@(e => KeyWasPressed(e))" 
@onkeydown:preventDefault="@PreventDefault" 
id="@GetId()" 
name="@GetId()" 
@bind-value="@InputValue" 
@bind-value:event="oninput" />

用户应该编写文本,但用户应该使用箭头键在列表中导航(所以我尽量防止光标移动到文本的顶部和末尾)。

在 JavaScript 中可能是这样的:

function KeyWasPressed(e)
{
    // key down
    if (e.keyCode == 40)
    {
        e.preventDefault();
        // some work...
    }
    // key up
    else if (e.keyCode == 38)
    {
        e.preventDefault();
        // some work...
    }
}

如何在 Blazor 中执行此操作?使用@onkeydown:preventDefault,您可以防止整个输入。如果我将它设置为一个变量 (@PreventDefault),我只能阻止 next 输入(因为第一个输入已经发生)。只是为了理解我的意思:

  • PreventDefault FALSE > 输入“H” > 将 PreventDefault 设置为 FALSE
  • PreventDefault FALSE > 输入“ArrowUp” > 将 PreventDefault 设置为 TRUE
  • PreventDefault TRUE > 输入“i” > 将 PreventDefault 设置为 FALSE

所以输入将是(| = 光标):H| > |H > |H

这意味着光标错误并且“i”被阻止了。

有什么想法吗?感谢您的建议。

【问题讨论】:

    标签: c# blazor


    【解决方案1】:

    不幸的是,目前没有简单的解决方案。对于这种情况,如果您想回调您的 .NET 代码,您仍然需要使用 JS 事件处理程序和一些互操作。

    您会在 https://github.com/dotnet/aspnetcore/issues/14517#issuecomment-559184498https://github.com/dotnet/aspnetcore/issues/14517#issuecomment-559184498处找到来自 Steve Sanderson 关于原因(异步处理程序)的非常简短的评论

    另一种解决方法是将输入绑定到变量并手动更新值。 (这里也指出PreventDefault on Blazor input )但这可能是一条崎岖不平的道路。

    就个人而言,我希望将 preventDefault 和 stopPropagation 视为传递给 C# 方法处理程序的 EventArgs 的一部分。我认为这在技术上具有挑战性。但是,它将简化许多用例。您可能想在 aspnetcore 上为此打开一个问题。

    【讨论】:

    • 感谢您的回答!似乎 Blazor 需要做更多的工作,直到它成为 JS 和 JS 框架的真正替代品 :( “PreventDefault on Blazor input”的东西似乎非常有限,复制/粘贴甚至带有大写的 TEXT 怎么样?这行不通。我的意思是我有一些类似的想法:阻止所有并将所有“允许”键附加到输入变量。但是您必须读取 shift 键并等待下一个输入添加诸如“A”(大写)之类的内容,这也是不好。
    【解决方案2】:

    我的解决方案如下。

    在 JS 中创建以下方法。它会捕捉到 UP 和 DOWN 键击。

    <script>
        function subscribeToChange(componentRef, inputRef) {
            console.log("subscribeToChange!");
    
            inputRef.onkeydown = function (event) {
                if (event.keyCode == "38") {
                    event.preventDefault();
    
                    console.log("Up key pressed");
                    componentRef.invokeMethodAsync('invokeFromJS');
                }
                else if (event.keyCode == "40") {
                    event.preventDefault();
    
                    console.log("Down key pressed");
                    componentRef.invokeMethodAsync('invokeFromJS');
                }
            };
    
            inputRef.onkeyup = function (event) {
                componentRef.invokeMethodAsync('setValueFromJS', inputRef.value);
            };
        }
    </script>
    

    剃须刀:

    <input @ref="Typing3" />
    @HelloFromJSStr
    

    在 razor.cs 中:

        public ElementReference Typing3;
        public string HelloFromJSStr = "";
    
        [JSInvokable("invokeFromJS")]
        public async Task HelloFromJS()
        {
            //HelloFromJSStr += "A";
            //StateHasChanged();
            // do something here on UP or DOWN button presses..
        }
    
        [JSInvokable("setValueFromJS")]
        public async Task SetValueFromJS(string newValue)
        {
            HelloFromJSStr = newValue;
            StateHasChanged();
        }
    

    在我的示例中,您有 2 种方法。被触发的onkeyup 可用于将 final 值设置为属性 (HelloFromJSStr )。如果任何其他 UI 元素需要重新渲染,然后调用 StateHasChanged() 方法,如示例所示。休息是你的想象。

    剩下的代码部分是初始化:

    public partial class EventsAndRendering
    {
        [Inject]
        protected IJSRuntime JSRuntime { get; set; }
    
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            Console.WriteLine($"{this.GetType().Name}: OnAfterRenderAsync. firstRender: {firstRender}");
    
            if (firstRender)
            {
                var componentRef = DotNetObjectReference.Create(this);
    
                await JSRuntime.InvokeAsync<object>("subscribeToChange", new object[] { componentRef, Typing3 });
            }
        }
    
        // HelloFromJS()
        // SetValueFromJS(string newValue)
    }
    

    DotNetObjectReference 允许我们从 JS 调用 C# 代码,而无需创建方法 statics。

    所以最后的流程如下:

    1. 第一次呈现页面后 -> 我们创建对主要组件的引用以及对 inpout 元素的引用。
    2. 然后我们使用上述引用来调用subscribeToChange JS 方法,该方法订阅我们输入元素上发生的事件。
    3. 在发生 keydown 事件时,我们会在 C# 中触发方法 HelloFromJS
    4. 在 keyup 事件时,我们触发 C# 中的方法 SetValueFromJS

    以上只是一个例子,必须根据需要进行调整:)

    灵感:https://docs.microsoft.com/en-us/aspnet/core/blazor/call-dotnet-from-javascript?view=aspnetcore-5.0#instance-method-call

    编辑:考虑实现IDisposable接口来处理.Net对象:

    public void Dispose()
    {
        componentRef?.Dispose();
    }
    

    【讨论】:

      猜你喜欢
      • 2021-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-08
      • 1970-01-01
      • 2017-01-20
      • 1970-01-01
      相关资源
      最近更新 更多