L'evento onKeyDown non funziona sui div in React


92

Voglio usare un evento keyDown su un div in React. Lo voglio:

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

Funziona bene, ma mi piacerebbe farlo di più in stile React. Provai

        onKeyDown={this.onKeyPressed}

sul componente. Ma non reagisce. Funziona su elementi di input come ricordo.

Codepen

Come posso farlo?


Personalmente mi piace il tuo approccio. Questo sembra un buon modo per associare i tratti chiave al documento, che è al di fuori dell'ambito del componente. e non richiede focus su un particolare elemento.
Daniel

Risposte:


159

Dovresti usare l' attributo tabIndex per poter ascoltare l' onKeyDownevento su un div in React. L'impostazione tabIndex="0"dovrebbe licenziare il gestore.


2
Sembra un design pessimo e supponente. E se volessi gestire un evento di bubbling su un elemento contenitore ma quel contenitore stesso non dovrebbe mai essere focalizzato?
Will P.

1
Questo mi sembra più un trucco o una soluzione alternativa. Potrebbe esserci un momento in cui è necessario che il div dato mantenga un ordine di tabulazione.
Iwnnay

9
tabIndex={-1}può essere utilizzato anche se stai lavorando con un elemento che non è interattivo e non desideri modificare l'ordine di tabulazione del documento.
IliasT

1
devi impostare tabIndex, per rendere il div focalizzabile. Puoi impostare tabIndex su 0,1, -1 ... Ma prima di farlo controlla questo webaim.org/techniques/keyboard/tabindex Probabilmente vorrai impostare -1 dato che lo stai manipolando a livello di programmazione .
Kavita

per qualche motivo questo funziona solo se ho un elemento <input> nel div con tabIndex. O qualcos'altro che può essere focalizzato. Con solo altri div, non è ancora in fase di acquisizione. qualche idea?
Flion

24

Devi scriverlo in questo modo

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

Se onKeyPressednon è associato a this, prova a riscriverlo usando la funzione freccia o collegalo nel componente constructor.


2
Scusate. Ne ero sicuro, ho appena trascurato questo. Ma non è questo il problema. Ancora non funziona.
Michael

risposta aggiornata. Dovresti fare clic sul div o portarlo a fuoco prima di premere qualsiasi tasto.
Panther

L'ho fatto. La sua non funziona. Ho aggiornato il codice sopra. Funziona bene con i comandi DOM, ma non nello stile React.
Michael

puoi spiegare cosa non funziona? la tua funzione non console.logviene richiamata o non restituisce nulla?
Panther

La funzione non viene chiamata. Ho un codepen: codepen.io/lafisrap/pen/OmyBYG . Riguarda le linee 275 e 307.
Michael,

7

Stai pensando troppo in puro Javascript. Sbarazzati dei tuoi ascoltatori su quei metodi del ciclo di vita React e usa event.keyinvece di event.keyCode(poiché questo non è un oggetto evento JS, è un React SyntheticEvent ). L'intero componente potrebbe essere così semplice (supponendo che non abbiate vincolato i vostri metodi in un costruttore).

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={this.onKeyPressed}
    >
      <div className="light-circle">
        <div className="image-wrapper">
          <img src={IMG_URL+player.img} />
        </div>
      </div>
    </div>
  )
}

È esattamente come volevo scriverlo. Ma diavolo, non sta andando. Ecco il codepen: codepen.io/lafisrap/pen/OmyBYG . Se si commenta la riga 275, l'immissione da tastiera (tasti cursore) non funziona. onKeyDown è sulla linea 307.
Michael,

keyCode che uso per i tasti cursore, poiché non restituiscono alcun carattere.
Michael

1
React non utilizza oggetti evento Javascript, quindi non esiste una proprietà keyCode. Questo eventoggetto è un Reagire SyntheticEvent .
acciaio

@Michael, inoltre, non sono del tutto sicuro di come si stia innescando un evento chiave su un div, ma quando inserisco questo codice in un violino con un onClickpuntello invece degli onKeyDownincendi del gestore.
acciaio

Grazie. Questo spiega ... Gli eventi chiave funzionano però nei campi di input.
Michael

2

La risposta con

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

funziona per me, tieni presente che tabIndex richiede un numero, non una stringa, quindi tabIndex = "0" non funziona.


Forse modificare l'altra risposta?
Ross Attrill

0

Usare il divtrucco con tab_index="0"o tabIndex="-1"funziona, ma ogni volta che l'utente focalizza una vista che non è un elemento, si ottiene un brutto contorno di messa a fuoco sull'intero sito web. Questo può essere risolto impostando il CSS per il div da utilizzare outline: nonenel focus.

Ecco l'implementazione con componenti in stile:

import styled from "styled-components"

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

e nella classe App:

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

-1

Ti manca l'associazione del metodo nel costruttore. Ecco come React ti suggerisce di farlo:

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

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

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

Ci sono altri modi per farlo, ma questo sarà il più efficiente in fase di esecuzione.


-3

Devi impedire l'attivazione dell'evento predefinito.

onKeyPressed(e) {
   e.preventDefault();
   console.log(e.key);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.