Подія onKeyDown не працює на divs в React


92

Я хочу використовувати подію keyDown на div у React. Я згоден:

  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

Як я можу це зробити?


Особисто мені подобається ваш підхід. Це виглядає як хороший спосіб прив’язати ключові штрихи до документа, який виходить за межі вашої складової. і не вимагає зосередження уваги на певному елементі.
Даніель

Відповіді:


159

Ви повинні використовувати атрибут tabIndex, щоб мати можливість прослуховувати onKeyDownподію на div в React. Параметр tabIndex="0"повинен запускати ваш обробник.


2
Це здається поганим, самовпевненим дизайном. Що робити, якщо я хочу обробити барботажну подію на елементі контейнера, але сам контейнер ніколи не повинен бути зосередженим?
Уілл П.

1
Для мене це здається більше руйнуванням чи обхідним шляхом. Може бути час, коли вам потрібно, щоб даний div підтримував порядок вкладок.
Iwnnay,

9
tabIndex={-1}також може використовуватися, якщо ви працюєте з елементом, який не є інтерактивним і не хочете змінювати порядок вкладок документа.
IliasT

1
вам потрібно встановити tabIndex, щоб зробити div сфокусованим. Ви можете встановити tabIndex на 0,1, -1 .... Але перед тим, як це зробити, перевірте це webaim.org/techniques/keyboard/tabindex Ви, ймовірно, захочете встановити значення -1, оскільки ви ним програмно маніпулюєте .
Кавіта

з якихось причин це працює, лише якщо у мене є елемент <input> у div із вкладкою tabIndex. Або щось інше, що можна сфокусувати. Просто з іншими div, його все ще не захоплюють. Будь-які думки?
Фліон

24

Вам потрібно написати це так

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

Якщо onKeyPressedце не пов’язано this, спробуйте переписати його за допомогою функції стрілки або прив’язати до компонента constructor.


2
Вибачте. Я був упевнений, що я просто пропустив це. Але це не проблема. Це все ще не працює.
Майкл

оновлена ​​відповідь. Вам слід або натиснути на div, або сфокусувати його перед натисканням будь-яких клавіш.
Пантера

Я зробив. Не працює. Я оновив код вище. Він чудово працює з командами DOM, але не в стилі React.
Майкл

Ви можете пояснити, що не працює? Ваша функція не console.logвикликається або нічого не виводить?
Пантера

Функція не викликається. У мене є codepen: codepen.io/lafisrap/pen/OmyBYG . Йдеться про рядки 275 та 307.
Майкл

7

Ви занадто багато думаєте на чистому 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={this.onKeyPressed}
    >
      <div className="light-circle">
        <div className="image-wrapper">
          <img src={IMG_URL+player.img} />
        </div>
      </div>
    </div>
  )
}

Саме так я хотів це написати. Але біса, це не йде. Ось кодpen: codepen.io/lafisrap/pen/OmyBYG . Якщо ви коментуєте рядок 275, тоді введення на клавіатурі (клавіші курсору) не працює. onKeyDown стоїть у черзі 307.
Майкл

keyCode, який я використовую для клавіш курсору, оскільки вони не повертають жодного символу.
Майкл

1
React не використовує об'єкти подій Javascript, тому немає властивості keyCode. Цей eventоб’єкт є React SyntheticEvent .
сталь

@Michael Я також не зовсім впевнений, як ти ініціюєш ключову подію на div, але коли я поміщаю цей код у скрипку з onClickпропіком замість onKeyDownобробника.
сталь

Дякую. Це пояснює це ... Однак ключові події працюють у полях введення.
Майкл

2

Відповідь с

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

працює для мене, зауважте, що tabIndex вимагає числа, а не рядка, тому tabIndex = "0" не працює.


Може редагувати іншу відповідь?
Росс Атрілл

0

Використовуючи divфокус tab_index="0"або tabIndex="-1"працює, але коли користувач фокусує погляд, який не є елементом, ви отримуєте некрасивий контур фокусування на всьому веб-сайті. Це можна виправити, встановивши CSS для div для використання 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} />);
  }
}

Є й інші способи зробити це, але це буде найефективнішим під час виконання.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.