onKeyDownイベントがReactのdivで機能しない


91

ReactのdivでkeyDownイベントを使用したいのですが。私がやります:

  componentWillMount() {
      document.addEventListener("keydown", this.onKeyPressed.bind(this));
  }

  componentWillUnmount() {
      document.removeEventListener("keydown", this.onKeyPressed.bind(this));
  }      

  onKeyPressed(e) {
    console.log(e.keyCode);
  }

  render() {
    let player = this.props.boards.dungeons[this.props.boards.currentBoard].player;
    return (
      <div 
        className="player"
        style={{ position: "absolute" }}
        onKeyDown={this.onKeyPressed} // not working
      >
        <div className="light-circle">
          <div className="image-wrapper">
            <img src={IMG_URL+player.img} />
          </div>
        </div>
      </div>
    )
  }

うまく動きますが、Reactスタイルでもっとやりたいです。私は試した

        onKeyDown={this.onKeyPressed}

コンポーネント上。しかし、それは反応しません。私が思い出すように、それは入力要素で動作します。

Codepen

どうすればできますか?


個人的に私はあなたのアプローチが好きです。これは、コンポーネントのスコープ外にあるドキュメントにキーストロークをバインドするための良い方法のように見えます。特定の要素に焦点を合わせる必要はありません。
ダニエル

回答:


155

Reactのdivでイベントをリッスンできるようにするには、tabIndex属性を使用する必要がありますonKeyDown。設定tabIndex="0"によりハンドラが起動されます。


1
これは悪い、独断的なデザインのようです。コンテナー要素のバブリングイベントを処理したいが、そのコンテナー自体がフォーカスされるべきではない場合はどうなりますか?
ウィルP.

1
これは私にとってハックまたは回避策のようです。特定のdivにタブオーダーを維持させる必要がある場合があります。
Iwnnay

8
tabIndex={-1}インタラクティブではない要素を使用していて、ドキュメントのタブ順序を変更したくない場合にも使用できます。
IliasT

1
divをフォーカス可能にするには、tabIndexを設定する必要があります。tabIndexを0,1、-1 ...に設定できますが、その前にこれを確認してください 。webaim.org/ techniques / keyboard / tabindex プログラムで操作しているので、おそらく-1に設定する必要があります。 。
カビタ

何らかの理由でこれが機能するのは、divにtabIndexを持つ<input>要素がある場合のみです。または集中できる他の何か。他のdivだけでは、まだキャプチャされていません。何かご意見は?
Flion

23

このように書く必要があります

<div 
    className="player"
    style={{ position: "absolute" }}
    onKeyDown={this.onKeyPressed}
    tabIndex="0"
  >

onKeyPressedバインドされていない場合はthis、矢印関数を使用して書き換えるか、コンポーネントにバインドしてくださいconstructor


1
ごめんなさい。きっとこれを見逃してしまいました。しかし、これは問題ではありません。まだ機能していません。
マイケル

回答を更新しました。キーを押す前に、divをクリックするか、divにフォーカスする必要があります。
パンサー

やった。動いていない。上記のコードを更新しました。DOMコマンドでは問題なく機能しますが、Reactスタイルでは機能しません。
マイケル

何が機能していないのか説明できますか?関数console.logが呼び出されていないか、何も出力していませんか?
パンサー

関数は呼び出されません。codepen:codepen.io/lafisrap/pen/OmyBYGがあります。275行目と307行目についてです。–
マイケル

6

純粋なJavascriptについて考えすぎています。これらのReactライフサイクルメソッドのリスナーを取り除き、event.key代わりに使用しますevent.keyCode(これはJSイベントオブジェクトではないため、React SyntheticEventです)。コンポーネント全体をこれと同じくらい単純にすることができます(コンストラクターでメソッドをバインドしていない場合)。

onKeyPressed(e) {
  console.log(e.key);
}

render() {
  let player = this.props.boards.dungeons[this.props.boards.currentBoard].player;
  return (
    <div 
      className="player"
      style={{ position: "absolute" }}
      onKeyDown={(e) => this.onKeyPressed(e)}
    >
      <div className="light-circle">
        <div className="image-wrapper">
          <img src={IMG_URL+player.img} />
        </div>
      </div>
    </div>
  )
}

それがまさに私がそれを書きたかった方法です。しかし、地獄、それは起こっていません。これがコードペンです:codepen.io/lafisrap/pen/OmyBYG。275行目にコメントを付けると、キーボード入力(カーソルキー)が機能しなくなります。onKeyDownは307行目です。–
マイケル

keyCodeは文字を返さないため、カーソルキーに使用します。
マイケル

1
ReactはJavascriptイベントオブジェクトを使用しないため、keyCodeプロパティはありません。そのeventオブジェクトはReact SyntheticEventです。

@Michaelまた、divでキーイベントをどのようにトリガーするかは完全にはわかりませんが、ハンドラーのonClick代わりにプロップを使用してこのコードをフィドルに配置すると、onKeyDown火災が発生します。

ありがとう。つまり、キーイベントは入力フィールドで機能します。
マイケル

1

答えは

<div 
    className="player"
    onKeyDown={this.onKeyPressed}
    tabIndex={0}
>

私には問題ありません。tabIndexには文字列ではなく数値が必要なので、tabIndex = "0"は機能しません。


0

またはでdivトリックを使用しても、ユーザーが要素ではないビューに焦点を合わせているときはいつでも、Webサイト全体に醜いフォーカスの概要が表示されます。これは、divが使用するCSSを設定することで修正できますtab_index="0"tabIndex="-1"outline: noneがフォーカスで。

スタイル付きコンポーネントを使用した実装は次のとおりです。

import styled from "styled-components"

const KeyReceiver = styled.div`
  &:focus {
    outline: none;
  }
`

そしてAppクラスで:

  render() {
    return (      
      <KeyReceiver onKeyDown={this.handleKeyPress} tabIndex={-1}>
          Display stuff...
      </KeyReceiver>
    )

-1

コンストラクターでメソッドのバインディングが欠落しています。これは、Reactが推奨する方法です。

class Whatever {
  constructor() {
    super();
    this.onKeyPressed = this.onKeyPressed.bind(this);
  }

  onKeyPressed(e) {
    // your code ...
  }

  render() {
    return (<div onKeyDown={this.onKeyPressed} />);
  }
}

これを行う方法は他にもありますが、これは実行時に最も効率的です。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.