Acara onKeyDown tidak berfungsi pada div di React


92

Saya ingin menggunakan acara keyDown pada div di React. Saya melakukan:

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

Ini berfungsi dengan baik, tetapi saya ingin melakukannya lebih banyak dalam gaya React. Saya mencoba

        onKeyDown={this.onKeyPressed}

pada komponen. Tapi itu tidak bereaksi. Ia bekerja pada elemen masukan seingat saya.

Codepen

Bagaimana saya bisa melakukannya?


Secara pribadi saya suka pendekatan Anda. Ini sepertinya cara yang baik untuk mengikat penekanan tombol ke dokumen, yang berada di luar cakupan komponen Anda. dan tidak membutuhkan fokus pada elemen tertentu.
Daniel

Jawaban:


159

Anda harus menggunakan atribut tabIndex agar dapat mendengarkan onKeyDownevent pada div di React. Pengaturan tabIndex="0"harus memecat pawang Anda.


2
Ini sepertinya desain yang buruk dan keras kepala. Bagaimana jika saya ingin menangani acara yang menggelegak pada elemen penampung tetapi penampung itu sendiri tidak boleh difokuskan?
Akan P.

1
Ini sepertinya lebih merupakan peretasan atau solusi bagi saya. Mungkin ada saat ketika Anda membutuhkan div yang diberikan untuk mempertahankan urutan tab.
Iwnnay

11
tabIndex={-1}juga dapat digunakan jika Anda bekerja dengan elemen yang tidak interaktif dan tidak ingin mengubah urutan tab dokumen.
IliasT

1
Anda harus mengatur tabIndex, untuk membuat div dapat difokuskan. Anda dapat menyetel tabIndex menjadi 0,1, -1 .... Namun sebelum Anda melakukannya, periksa webaim.org/techniques/keyboard/tabindex Anda mungkin ingin menyetel -1 karena Anda memanipulasinya secara terprogram .
Kavita

untuk beberapa alasan ini hanya berfungsi jika saya memiliki elemen <input> di div dengan tabIndex. Atau hal lain yang bisa difokuskan. Hanya dengan div lain, masih belum menangkap. Ada pemikiran?
Flion

24

Anda perlu menulisnya seperti ini

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

Jika onKeyPressedtidak terikat this, coba tulis ulang menggunakan fungsi panah atau ikat di komponen constructor.


2
Maaf. Saya yakin, saya hanya mengabaikan ini. Tapi bukan itu masalahnya. Ini masih belum berhasil.
Michael

jawaban yang diperbarui. Anda harus mengklik div atau membuatnya fokus sebelum menekan tombol apa pun.
Panther

Aku melakukannya. Ini tidak bekerja. Saya memperbarui kode di atas. Ini berfungsi dengan baik dengan perintah DOM, tetapi tidak dalam gaya React.
Michael

dapatkah Anda menjelaskan apa yang tidak berhasil? apakah fungsi Anda tidak dipanggil atau tidak menghasilkan console.logapa-apa?
Panther

Fungsi tidak dipanggil. Saya memiliki codepen: codepen.io/lafisrap/pen/OmyBYG . Ini tentang baris 275 dan 307.
Michael

7

Anda terlalu banyak berpikir dalam Javascript murni. Singkirkan listener Anda pada metode siklus hidup React dan gunakan event.keysebagai ganti event.keyCode(karena ini bukan objek event JS, ini adalah React SyntheticEvent ). Seluruh komponen Anda bisa sesederhana ini (dengan asumsi Anda belum mengikat metode Anda dalam konstruktor).

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

Persis seperti itulah saya ingin menulisnya. Tapi persetan, itu tidak pergi. Ini codepennya: codepen.io/lafisrap/pen/OmyBYG . Jika Anda memberi komentar pada baris 275 maka input papan kunci (tombol kursor) tidak berfungsi. onKeyDown berada di baris 307.
Michael

keyCode Saya gunakan untuk tombol kursor, karena mereka tidak mengembalikan karakter.
Michael

1
React tidak menggunakan objek event Javascript, jadi tidak ada properti keyCode. Itu eventobjek adalah Bereaksi SyntheticEvent .
baja

@ Michael Saya juga tidak sepenuhnya yakin bagaimana Anda memicu peristiwa kunci pada div, tetapi ketika saya memasukkan kode ini ke dalam biola dengan onClickpenyangga alih-alih onKeyDownapi penangan.
baja

Terima kasih. Itu menjelaskannya ... Acara utama bekerja di bidang masukan.
Michael

2

Jawabannya dengan

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

berfungsi untuk saya, harap perhatikan bahwa tabIndex memerlukan angka, bukan string, jadi tabIndex = "0" tidak berfungsi.


Mungkin mengedit jawaban yang lain?
Ross Attrill

1

Menggunakan divtrik dengan tab_index="0"atau tabIndex="-1"berfungsi, tetapi setiap kali pengguna memfokuskan tampilan yang bukan elemen, Anda mendapatkan garis besar fokus yang jelek di seluruh situs web. Ini bisa diperbaiki dengan menyetel CSS untuk div yang akan digunakan outline: nonedalam fokus.

Berikut implementasinya dengan komponen bergaya:

import styled from "styled-components"

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

dan di kelas Aplikasi:

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

-1

Anda kehilangan pengikatan metode di konstruktor. Beginilah cara React menyarankan Anda melakukannya:

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

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

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

Ada cara lain untuk melakukan ini, tetapi ini akan menjadi yang paling efisien saat runtime.


-3

Anda harus mencegah peristiwa default memicu.

onKeyPressed(e) {
   e.preventDefault();
   console.log(e.key);
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.