Das onKeyDown-Ereignis funktioniert nicht mit Divs in React

91

Ich möchte ein keyDown-Ereignis für ein div in React verwenden. Ich mache:

  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>
    )
  }

Es funktioniert gut, aber ich würde es gerne mehr im React-Stil machen. Ich habe es versucht

        onKeyDown={this.onKeyPressed}

auf der Komponente. Aber es reagiert nicht. Soweit ich mich erinnere, funktioniert es mit Eingabeelementen.

Codepen

Wie kann ich es tun?

Michael
quelle
Persönlich mag ich Ihren Ansatz. Dies scheint eine gute Möglichkeit zu sein, die Tastenanschläge an das Dokument zu binden, das außerhalb des Bereichs Ihrer Komponente liegt. und erfordert keine Konzentration auf ein bestimmtes Element.
Daniel

Antworten:

153

Sie sollten das tabIndex- Attribut verwenden, um ein onKeyDownEreignis in einem Div in React abhören zu können . Die Einstellung tabIndex="0"sollte Ihren Handler auslösen.

Burakhan Alkan
quelle
1
Dies scheint ein schlechtes, einfühlsames Design zu sein. Was ist, wenn ich ein sprudelndes Ereignis auf einem Containerelement behandeln möchte, dieser Container selbst jedoch niemals fokussiert werden sollte?
Will P.
1
Dies scheint mir eher ein Hack oder eine Problemumgehung zu sein. Es kann vorkommen, dass das angegebene Div eine Tabulatorreihenfolge beibehalten muss.
Iwnnay
7
tabIndex={-1}kann auch verwendet werden, wenn Sie mit einem Element arbeiten, das nicht interaktiv ist und die Tabulatorreihenfolge des Dokuments nicht ändern möchten.
IliasT
1
Sie müssen den tabIndex festlegen, um das div fokussierbar zu machen. Sie können den tabIndex auf 0,1, -1 ... setzen. Bevor Sie dies tun, lesen Sie dies unter webaim.org/techniques/keyboard/tabindex. Sie möchten wahrscheinlich -1 setzen, da Sie ihn programmgesteuert bearbeiten .
Kavita
Aus irgendeinem Grund funktioniert dies nur, wenn ich ein <input> -Element im div mit dem tabIndex habe. Oder etwas anderes, das fokussiert werden kann. Mit nur anderen Divs wird es immer noch nicht erfasst. Irgendwelche Gedanken?
Flion
23

Sie müssen es so schreiben

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

Wenn dies onKeyPressednicht gebunden ist this, versuchen Sie, es mithilfe der Pfeilfunktion neu zu schreiben oder in die Komponente zu binden constructor.

Panther
quelle
1
Es tut uns leid. Ich war mir sicher, ich habe das einfach übersehen. Das ist aber nicht das Problem. Es funktioniert immer noch nicht.
Michael
aktualisierte Antwort. Sie sollten entweder auf das Div klicken oder es fokussieren, bevor Sie eine Taste drücken.
Panther
Ich tat. Es funktioniert nicht. Ich habe den obigen Code aktualisiert. Es funktioniert gut mit den DOM-Befehlen, jedoch nicht im React-Stil.
Michael
Kannst du erklären, was nicht funktioniert? Wird Ihre Funktion nicht aufgerufen oder console.loggibt sie nichts aus?
Panther
Die Funktion wird nicht aufgerufen. Ich habe einen Codepen: codepen.io/lafisrap/pen/OmyBYG . Es geht um die Zeilen 275 und 307.
Michael
6

Sie denken zu viel in reinem Javascript. Befreien Sie sich von Ihren Listenern für diese React-Lebenszyklusmethoden und verwenden Sie event.keystattdessen event.keyCode(da dies kein JS-Ereignisobjekt ist, sondern ein React SyntheticEvent ). Ihre gesamte Komponente könnte so einfach sein (vorausgesetzt, Sie haben Ihre Methoden nicht in einem Konstruktor gebunden).

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>
  )
}
Stahl
quelle
Genau so wollte ich es schreiben. Aber zum Teufel geht es nicht. Hier ist der Codepen: codepen.io/lafisrap/pen/OmyBYG . Wenn Sie Zeile 275 kommentieren, funktioniert die Tastatureingabe (Cursortasten) nicht. onKeyDown ist in Zeile 307.
Michael
keyCode Ich verwende für Cursortasten, da sie kein Zeichen zurückgeben.
Michael
1
React verwendet keine Javascript-Ereignisobjekte, daher gibt es keine keyCode-Eigenschaft. Dieses eventObjekt ist ein React SyntheticEvent .
Stahl
@Michael Ich bin mir auch nicht ganz sicher, wie Sie ein Schlüsselereignis auf einem Div auslösen, aber wenn ich diesen Code mit einer onClickRequisite anstelle des Handlerfeuers in eine Geige onKeyDownstecke.
Stahl
Vielen Dank. Das erklärt es ... Die Schlüsselereignisse funktionieren jedoch in Eingabefeldern.
Michael
1

Die Antwort mit

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

funktioniert für mich, bitte beachten Sie, dass der tabIndex eine Zahl und keine Zeichenfolge erfordert, sodass tabIndex = "0" nicht funktioniert.

beschäftigte Biene
quelle
-1

Sie vermissen die Bindung der Methode im Konstruktor. So schlägt React vor, dass Sie es tun:

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

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

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

Es gibt andere Möglichkeiten, dies zu tun, aber dies ist zur Laufzeit am effizientesten.

Iwnnay
quelle
-2

Sie müssen verhindern, dass das Standardereignis ausgelöst wird.

onKeyPressed(e) {
   e.preventDefault();
   console.log(e.key);
}
Boluwatife Fakorede
quelle