onKeyDown olayı React'teki div'ler üzerinde çalışmıyor


92

React'teki bir div üzerinde keyDown olayını kullanmak istiyorum. Yaparım:

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

İyi çalışıyor, ancak bunu daha çok React tarzında yapmak istiyorum. denedim

        onKeyDown={this.onKeyPressed}

bileşen üzerinde. Ama tepki vermiyor. Hatırladığım kadarıyla girdi öğeleri üzerinde çalışıyor.

Codepen

Nasıl yapabilirim?


Şahsen yaklaşımınızı beğendim. Bu, bileşeninizin kapsamı dışında kalan tuş vuruşlarını belgeye bağlamanın iyi bir yolu gibi görünüyor. ve belirli bir öğeye odaklanmayı gerektirmez.
Daniel

Yanıtlar:


159

React'teonKeyDown bir div üzerindeki olayı dinleyebilmek için tabIndex niteliğini kullanmalısınız . Ayar tabIndex="0", işleyicinizi ateşlemelidir.


2
Bu kötü, kararlı bir tasarıma benziyor. Ya bir kap öğesinde köpüren bir olayı işlemek istiyorsam, ancak bu kabın kendisi hiçbir zaman odaklanmamalıdır?
Will P.

1
Bu bana daha çok bir hack veya geçici çözüm gibi görünüyor. Verilen div'in bir sekme sırası tutmasına ihtiyaç duyduğunuz bir zaman olabilir.
Iwnnay

11
tabIndex={-1}Etkileşimli olmayan bir öğeyle çalışıyorsanız ve belgenin sekme sırasını değiştirmek istemiyorsanız da kullanılabilir.
IliasT

1
div'i odaklanabilir hale getirmek için tabIndex'i ayarlamanız gerekir. TabIndex'i 0,1, -1 olarak ayarlayabilirsiniz .... Ama bunu yapmadan önce webaim.org/techniques/keyboard/tabindex'e bakın , programlı olarak işlediğiniz için muhtemelen -1'i ayarlamak isteyeceksiniz. .
Kavita

bazı nedenlerden dolayı bu yalnızca div'de tabIndex ile bir <input> öğesine sahipsem çalışır. Veya odaklanılabilecek başka bir şey. Sadece diğer div'lerle, hala yakalamıyor. Düşüncesi olan var mı?
Flion

24

Bu şekilde yazmalısın

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

onKeyPressedBağlı değilse , thisok işlevini kullanarak yeniden yazmaya çalışın veya bileşene bağlayınconstructor .


2
Afedersiniz. Emindim, sadece bunu göz ardı ettim. Ama sorun bu değil. Hala çalışmıyor.
Michael

güncellenmiş cevap. Herhangi bir tuşa basmadan önce div öğesine tıklamanız veya odak noktasına getirmeniz gerekir.
Panther

Yaptım. Çalışmıyor. Yukarıdaki kodu güncelledim. DOM komutlarıyla sorunsuz çalışır, ancak React tarzında çalışmaz.
Michael

neyin çalışmadığını açıklayabilir misin? işleviniz çağrılmıyor mu veya console.loghiçbir şey çıkmıyor mu?
Panther

İşlev çağrılmaz. Codepen'im var: codepen.io/lafisrap/pen/OmyBYG . 275 ve 307 numaralı satırlar hakkında.
Michael

7

Saf Javascript ile çok fazla düşünüyorsun. Bu React yaşam döngüsü yöntemlerinde dinleyicilerinizden kurtulun ve event.keyyerine kullanın event.keyCode(çünkü bu bir JS olay nesnesi değildir, bir React SyntheticEvent'tir ). Bileşeninizin tamamı bu kadar basit olabilir (yöntemlerinizi bir yapıcıda bağlamadığınızı varsayarak).

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

Ben de aynen böyle yazmak istedim. Ama cehennem, gitmiyor. İşte codepen: codepen.io/lafisrap/pen/OmyBYG . 275 satırına yorum yaparsanız, klavye girişi (imleç tuşları) çalışmaz. onKeyDown 307. satırda.
Michael

keyCode Hiçbir karakter döndürmediklerinden imleç tuşları için kullanıyorum.
Michael

1
React, Javascript olay nesnelerini kullanmaz, bu nedenle keyCode özelliği yoktur. Bu eventnesne bir React SyntheticEvent'tir .
çelik

@Michael Ayrıca bir div üzerinde anahtar bir olayı nasıl tetiklediğinizden tam olarak emin değilim, ancak bu kodu eylemci onClickyerine bir prop ile bir keman içine koyduğumda ateşleniyor onKeyDown.
çelik

Teşekkürler. Bu onu açıklıyor ... Anahtar olaylar yine de giriş alanlarında çalışır.
Michael

2

İle cevap

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

benim için çalışıyor, lütfen tabIndex'in bir dize değil bir sayı gerektirdiğini unutmayın, bu nedenle tabIndex = "0" çalışmaz.


Belki diğer yanıtı düzenlersiniz?
Ross Attrill

1

divHile ile kullanmak tab_index="0"veya tabIndex="-1"işe yarıyor, ancak kullanıcı öğe olmayan bir görünüme odaklandığında, tüm web sitesinde çirkin bir odak çizgisi elde edersiniz. Bu, div'in kullanması için CSS'yi ayarlayarak düzeltilebiliroutline: none , odakta .

İşte stilli bileşenlerle uygulama:

import styled from "styled-components"

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

ve Uygulama sınıfında:

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

-1

Yapıcıdaki yöntemin bağlamasını kaçırıyorsunuz. React, bunu yapmanızı şöyle öneriyor:

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

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

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

Bunu yapmanın başka yolları da vardır, ancak bu, çalışma zamanında en verimli olanı olacaktır.


-3

Varsayılan olayın tetiklenmesini önlemelisiniz.

onKeyPressed(e) {
   e.preventDefault();
   console.log(e.key);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.