【问题标题】:How to bind on document events with blazor如何使用 blazor 绑定文档事件
【发布时间】:2019-08-16 17:00:21
【问题描述】:

我尝试在 Blazor 上编写一个简单的蛇游戏,但我找不到任何方法将我的事件绑定到文档上。
有机会在不同的元素上绑定事件,例如 divinput
比如:<input onkeypress="@KeyPressInDiv"/>
在哪里public void KeyPressInDiv(UIKeyboardEventArgs ev) {....}
我想,应该有一个 javascript 方法 document.onkeydown = function (evt) {} 的类比 我找到了几种解决此问题的方法:
1)使用JS进行绑定和调用blazor代码(取自https://github.com/aesalazar/AsteroidsWasm

document.onkeydown = function (evt) {
  evt = evt || window.event;
  DotNet.invokeMethodAsync('Test.ClientSide', 'JsKeyDown', evt.keyCode);

  //Prevent all but F5 and F12
  if (evt.keyCode !== 116 && evt.keyCode !== 123)
      evt.preventDefault();
};

document.onkeyup = function (evt) {
  evt = evt || window.event;
  DotNet.invokeMethodAsync('Test.ClientSide', 'JsKeyUp', evt.keyCode);

  //Prevent all but F5 and F12
  if (evt.keyCode !== 116 && evt.keyCode !== 123)
      evt.preventDefault();
};

并在 c# 中实现一个静态类,其方法由 [JSInvokable] 和事件标记。
这项工作,但会导致每次印刷机都出现严重延迟
2) 这可以在其上添加输入标签和绑定事件。
这将比以前更快,但是:
- 它主要看起来像一个哈克然后是一个解决方案
- 我们无法捕捉到许多动作,例如向上/向下箭头

是否有直接绑定来自 blazor 的文档事件的方法?
更新 1:我创建了简单的项目以更好地解释我试图实现的目标。 https://github.com/XelMed/BlazorSnake
Snake 有 3 个实现:
1) 纯 js - 这是预期的行为
2) 使用带有 blazor 的 js - 从带有 JsInterop 的 JS 代码中调用 blazor 函数
3) 使用输入标签 - 控制 Snake 的输入标签上的绑定事件

【问题讨论】:

  • 您看到了多少延迟?当我在 JS 和接收它的 C# 方法中记录按键时,我看不到超过 1-2 毫秒的差异。这就是日志语句——没有它们可能更少。

标签: .net-core blazor


【解决方案1】:

也许使用 JsInterop 向文档添加一个事件侦听器,并为使用偶数参数调用 C# 方法的事件分配一个匿名函数。

例如你的 JsInterop.js:

document.addEventListener('onkeypress', function (e) {
    DotNet.invokeMethodAsync('Snake', 'OnKeyPress', serializeEvent(e))
});

将serializeEvent 作为follos 以避免一些古怪:

var serializeEvent = function (e) {
    if (e) {
        var o = {
            altKey: e.altKey,
            button: e.button,
            buttons: e.buttons,
            clientX: e.clientX,
            clientY: e.clientY,
            ctrlKey: e.ctrlKey,
            metaKey: e.metaKey,
            movementX: e.movementX,
            movementY: e.movementY,
            offsetX: e.offsetX,
            offsetY: e.offsetY,
            pageX: e.pageX,
            pageY: e.pageY,
            screenX: e.screenX,
            screenY: e.screenY,
            shiftKey: e.shiftKey
        };
        return o;
    }
};

在您的 C# 代码中,您将拥有:

[JSInvokable]
public static async Task OnMouseDown(UIMouseEventArgs e){
    // Do some stuff here
}

【讨论】:

  • 有用的答案。我之前没有意识到,如果没有序列化,就不可能将原始事件传递给 Blazor。
【解决方案2】:

我和你有同样的要求,我设法使用 invokeMethodAsync 将文档事件(例如 keydown)连接到我的 Razor 方法,但后来我发现我错过了 Blazor 提供的自动 DOM 差异和更新,如果Razor 方法更改了绑定到 HTML 元素的某些状态(例如控制 div 元素的可见性)。

似乎(根据我对 Blazor 的有限理解)通常 Blazor 在 WebAssembly 方法的返回数据中返回更新 DOM 所需的任何状态数据。 但是,如果您使用 JavaScript 中的 invokeMethod 或 invokeMethodAsync,您必须自己管理返回和使用这些数据,但这可能会出现问题,因为您的更新可能与 Blazor 的 DOM 状态视图冲突。

所以我想出了一个在我的 Razor 视图中生成隐藏按钮的 hacky 方法,例如:

<button id="arrow-left-button" @onclick="HandleArrowLeftPress"></button>

然后在 JavaScript 端,我连接了一个文档事件,该事件通过 Id 找到该按钮并在其上调用 .click():

document.getElementById('arrow-left-button').click();

我知道这看起来真的很糟糕,但它适用于我正在做的事情,即使用箭头键在屏幕上移动一个绝对定位的元素。

如果有人知道更简洁的方法(例如如何在处理程序回调中通过 JavaScript 端的名称强制更新 Razor 视图),请告诉我。

【讨论】:

    【解决方案3】:

    我遇到了类似的情况并使用以下方法作为解决方法。您将事件侦听器添加到 div 标记,然后将焦点设置到该 div 以便可以捕获您的按键。

    <div tabindex="0" @ref="container" @onkeydown="onKeyDown" id="container">
    //your snake game markup
    </div>
    @code {
        ElementReference container;
        protected override async Task OnAfterRenderAsync(bool firstRender) {
            await container.FocusAsync();
        }
        private void onKeyPress(KeyboardEventArgs obj) { //your code here. }
    }
    

    您可能需要移除div标签的焦点边框:

    #container:focus-visible {
        outline: none;
    }
    #container:focus {
        outline: none;
    }
    

    【讨论】:

      【解决方案4】:

      您可以将事件直接绑定到 C# 方法,只需使用您需要的事件标记(onkeyup/onmousemove ....)。

      @page "/"
      
      <div>
          <input type="text" onkeyup=@KeyUp />
      </div>
      @functions {
          void KeyUp(UIKeyboardEventArgs e)
          {
              Console.WriteLine(e.Key);
          }
      
          protected override Task OnInitAsync()
          {
              return Task.CompletedTask;
          }
      }
      

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-18
      • 2019-11-08
      • 1970-01-01
      • 1970-01-01
      • 2020-05-30
      • 1970-01-01
      • 2016-06-25
      • 2021-03-16
      相关资源
      最近更新 更多