[React] 가상키보드 - Keyboard Event

방예서·2022년 5월 30일
1

React

목록 보기
5/9
post-custom-banner

Event

  • 이벤트 버블링
    이벤트가 발생하면 상위 요소로 전파 된다.

  • target
    이벤트가 실제로 발생한 요소. 내가 클릭한 자식 요소를 반환

  • currentTarget
    이벤트가 부착된 부모의 위치를 반환

=> 키보드 클릭 이벤트에서 모든 키들에게 eventListener를 부여해주는 것은 비효율적. 이벤트의 동작방식을 이용해서 효율적으로 동작하도록 작성하자.


코드 리팩토링

  • assignEl()
this.#switchEl = document.getElementById("switch");
this.#fontSelectEl = document.getElementById("font");

switch와 font를 document에서 찾고 있다.
두 요소가 container라는 요소에 감싸져 있기 때문에, container라는 요소를 찾은 뒤 거기서 찾도록 한다.

  #assignEl() {
    this.#containerEl = document.getElementById("container");
    this.#switchEl = this.#containerEl.querySelector("#switch");
    this.#fontSelectEl = this.#containerEl.querySelector("#font");
  }
  

* getElementById는 document에서만 사용할 수 있다.
-> 우리가 찾은 container에서 요소 찾기 위해서는 querySelector를 사용한다.

  • addEvent()

  #addEvent() {
    this.#switchEl.addEventListener("change", this.#onChangeTheme);
    this.#fontSelectEl.addEventListener("change", this.#onChangeFont);
  }

  #onChangeTheme(e) {
    document.documentElement.setAttribute(
      "theme",
      e.target.checked ? "dark-mode" : ""
    );
  }

  #onChangeFont(e) {
    document.body.style.fontFamily = e.target.value;
  }
  

두 event handler를 분리하였다.

Keyboard Event

key Event에 나오는 code를 이용해서 key Event handler를 작성한다.

    document.addEventListener("keydown", (e) => {
      this.#keyboardEl
        .querySelector(`[data-code=${e.code}]`)
        .classList.add("active");
    });
    document.addEventListener("keyup", (e) => {
      this.#keyboardEl
        .querySelector(`[data-code=${e.code}]`)
        .classList.remove("active");
    });

html에 미리 작성되어 있는 data-code와 키보드에 누른 값의 code가 같은 요소를 불러와서, css에 작성한 active class를 추가해준다.

keyup(키보드 뗐을 때)도 반대로 동작하게 작성한다.

다만 해당 강의에서 tab이나 Caps Locks 등 몇몇 키는 작동하지 않게 해놓아서 if문으로 해당 요소 값이 있을 때만 classList add/remove 동작하게 처리해주어야 한다.

혹은 optional chaining을 사용해서 간결하게 작성할 수도 있다.

this.#keyboardEl
  .querySelector(`[data-code=${e.code}]`)
    ?.classList.add("active");

?. 연산자는 만약 참조가 null 또는 undefined이라면, 에러가 발생하는 것 대신에 표현식의 리턴 값은 undefined로 단락된다!


key event 처리 중 한글을 입력하면 에러 메시지를 띄우는 작업 중 e.key랑 한글 정규식을 아무리 비교해도 제대로 작동하지 않았다.

event를 확인해보니 한글은 아무리 눌러도 key나 code에 제대로된 값이 나오지 않고 Process라는 값이 나왔다.
그리고 input에 커서를 두지 않고 그냥 키보드를 입력할 때는 아예 한글모드가 먹히지도 않는다. (왜지?)

이 정보가 맞는지는 모르겠지만 하여튼 한글 자판 입력시 IME에서 메시지를 가로채서 생기는 현상인 것 같기도 하다.

https://circus7.tistory.com/6

일단 classList.toggle을 사용하여 한글 입력 시 에러 메시지를 띄우는데, 한글 정규식 말고 key==="Process" 라는 조건으로 임시 방편 해두었다.


한글 입력 시 input 에서 아예 입력을 못하게(보이는) 동작을 구현한다.

    document.addEventListener("input", () => {
      this.#inputEl.value = this.#inputEl.value.replace(
        /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/,
        ""
      );
    });

input으로 한글이 입력되는 순간, 빈스트링으로 replace 시켜준다.
입력이 안되는 것처럼 보이지만 사실은 순간적으로 input 값을 바꿔버리는 것이다.

(여기서는 또 한글 정규식이 잘 동작하는 것 같다.)


이벤트 핸들러를 구분해서 작성해야하니 그 작업을 또 해주었다. (미리 좀 해주지...)

    document.addEventListener("keydown", this.#onKeydown.bind(this));
    document.addEventListener("keyup", this.#onKeyup.bind(this));
    this.#inputEl.addEventListener("input", this.#onInput.bind(this));
                            

.bind(this)를 명시해주지 않으면 this가 document로 인식되어서 제대로 작동하지 않는다.

호출하는 함수에 객체를 바인딩 해주지 않으면 자바스크립트는 전역 객체로부터 값을 받아오려고 하기 때문에 내가 원하는 값이 아닌 다른 값을 가지게 된다. 그래서 우리는 생성자에서 컴포넌트 객체에 this의 이벤트 핸들러를 바인딩 해주는 것이다.

https://llighter.github.io/bind-method/

profile
console.log('bang log');
post-custom-banner

0개의 댓글