30개의 프로젝트로 배우는 프론트엔드 with VanillaJS - (1-2) 가상키보드

productuidev·2022년 8월 8일
0

FE Study

목록 보기
47/67
post-thumbnail
post-custom-banner

[fastcampus] 30개의 프로젝트로 배우는 프론트엔드 with VanillaJS (1-2)

간단하게 정리

(1) 가상키보드 기능 구현

  • Keyboard Event 적용
  • Mouse Event 적용

이전 코드 리팩토링

  • 이전은 document에서 element를 찾는 방식이었다면..
  • container를 먼저 찾아두고, menu나 input-group, keyboard element를 찾는 방식으로 간단하게 개선

src/js/keyboard.js

export class Keyboard {
  #swichEl;
  #fontSelectEl;
  #containerEl; 
  
  constructor() {
    this.#assignElement();
    this.#addEvent();
  }
  
  #assignElement() {
    this.#containerEl = document.getElementById("container"); // 컨테이너를 먼저 찾고
    this.#swichEl = this.#containerEl.querySelector("#switch"); // 토글
    this.#fontSelectEl = this.#containerEl.querySelector("#font"); // 폰트
  }
  
  #addEvent() {
    this.#swichEl.addEventListener("change", this.#onChangeTheme); // 테마변경
    this.#fontSelectEl.addEventListener("change", this.#onChangeFont); // 폰트변경
  }
 
   #onChangeTheme(event) {
    document.documentElement.setAttribute(
      "theme",
      event.target.checked ? "dark-mode" : ""
    );
  }

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

Keyboard Event

  • Input 입력 시 어떤 키가 눌리는지 알려주는 키보드 구현
  • Keyboard Event - 이벤트 버블링
  • Input에만 걸면 어떤 키가 눌렸는지 알 수 없다
  • document에 걸면 event를 걸면 input에 focus in/out 시 어떤 키가 눌렸는지 구현 가능

document에 keyboard event 걸기

src/js/keyboard.js

#addEvent() {
	
    ...
    
	document.addEventListner("keydown", (event)=>{
    	console.log("keydown");
        console.log(event.code);
    })
    document.addEventListner("keyup", (event)=>{
    	console.log("keyup");
    })
    
}
  • console 창 확인하여 key up/down 체크 후
  • KeyboardEvent 속성에서 key, code 속성 활용 (무슨 값을 입력했는지 알 수 있다)
  • 제공된 HTML의 data-code (key code) 기반으로 키보드 변화 주기
<div class="keyboard id="keyboard">
	<div class="row">
		<div class="key" data-code="KeyQ" data-val="q">Q</div>
		<div class="key" data-code="KeyW" data-val="w">W</div>
		.
		.
		.
    </div>
</div>

src/js/keyboard.js

export class Keyboard {

  #keyboardEl;
  
  constructor() {
    this.#assignElement();
    this.#addEvent();
  }

  #assignElement() {
    this.#keyboardEl = this.#containerEl.querySelector("#keyboard");
  }

  #addEvent() {
    document.addEventListener("keydown", (event) => {
      // console.log("keydown");
      // console.log(event.code);
      // 조건 key code 찾으면 (치환)
      if (this.#keyboardEl.querySelector(`[data-code=${event.code}]`)) {
        this.#keyboardEl
          .querySelector(`[data-code=${event.code}]`)
          .classList.add("active"); // active 클래스 추가
      }
    });
    document.addEventListener("keyup", (event) => {
      // console.log("keyup");
      // keyup도 똑같이
      if (this.#keyboardEl.querySelector(`[data-code=${event.code}]`)) {
        this.#keyboardEl
          .querySelector(`[data-code=${event.code}]`)
          .classList.remove("active");
      }
    });
  }
  
}
  • function Key를 찾지 못할 수 있어 if문

optional chaining

  • if문보다 더 간단한 처리 방법
    document.addEventListener("keydown", (event) => {
      this.#keyboardEl
        .querySelector(`[data-code=${event.code}]`)
        ?.classList.add("active"); // optional chaining
    });
    document.addEventListener("keyup", (event) => {
      this.#keyboardEl
        .querySelector(`[data-code=${event.code}]`)
        ?.classList.remove("active"); // optional chaining
    });

. 대신 ?. 사용하여 obj.first.secondp에 접근하기 전 obj.first가 null 또는 undefined가 아니라는 것을 암묵적으로 확인 (null이나 undefined면 자동으로 undefined 뱉음)

let nestedProp = obj.first?.second;

영문 키만 입력

정규표현식을 사용하여 영문 키가 아닌 한글 입력 시 한글 입력 불가 error alert message 보여주기

  #addEvent() {

    document.addEventListener("keydown", (event) => {
      // console.log("keydown");
      // console.log(event.code);
      // console.log(event.key, /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/.test(event.key));
      this.#inputGroupEl.classList.toggle(
        "error",
        /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/.test(event.key)
      );

    });

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

이벤트 분리하여 코드 수정

  #addEvent() {
    this.#swichEl.addEventListener("change", this.#onChangeTheme);
    this.#fontSelectEl.addEventListener("change", this.#onChangeFont);
    document.addEventListener("keydown", this.#onKeyDown.bind(this)); //
    document.addEventListener("keyup", this.#onKeyUp.bind(this)); // 
    this.#inputEl.addEventListener("input", this.#onInput);
  }

  #onInput(event) {
    event.target.value = event.target.value.replace(/[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/, "");
  }

  #onKeyDown(event) {
    this.#inputGroupEl.classList.toggle(
      "error",
      /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/.test(event.key)
    );

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

  #onKeyUp(event) {
    this.#keyboardEl
      .querySelector(`[data-code=${event.code}]`)
      ?.classList.remove("active"); // optional chaining
  }


비 많이 온다 😢

profile
필요한 내용을 공부하고 저장합니다.
post-custom-banner

0개의 댓글