keyboard.js 리팩토링
리팩토링 전
#assignElement() {
this.#switchEl = document.getElementById("switch");
this.#fontSelectEl = document.getElementById("font");
}
리팩토링 후
#assignElement() {
// document단이 아닌 container단에서 요소를 찾음으로 비용이 절감됨
this.#containerEl = document.getElementById("container");
this.#switchEl = this.#containerEl.querySelector("#switch");
this.#fontSelectEl = this.#containerEl.querySelector("#font");
this.#keyboardEl = this.#containerEl.querySelector("#keyboard");
this.#inputGropuEl = this.#containerEl.querySelector("#input-group");
this.#inputEl = this.#inputGropuEl.querySelector("#input");
}
모든 요소를 document에서부터 찾으면 비용과 시간이 많이 소요된다. 이를 최적화 하기 위해 모든 요소를 감싸는 container 요소에서부터 다른 요소들을 찾게 한다.
getElementById는 document 단에서만 사용가능하기때문에 querySelector로 변경한다.
이벤트 핸들러들은 최적화를 위해 코드를 분리한다.
// 이벤트 핸들러들은 최적화를 위해 코드를 분리함
#onChangeTheme(event) {
// console.log(event.target.checked);
// true 일때 다크테마 적용
document.documentElement.setAttribute(
"theme",
event.target.checked ? "dark-mode" : ""
);
}
#onChangeFont(event) {
// console.log(event.target.value); // font 값
document.body.style.fontFamily = event.target.value; // body의 font를 수정
}
키보드 이벤트 추가
이벤트가 작동될 때는 input에 직접 내용이 입력되거나, 키보드로 키를 직접 눌렀을때이다.
각각의 요소에 이벤트를 걸어주기보다는 document를 이벤트 대상으로 하고, 이벤트 버블링을 이용할 것이다.
이렇게 되면 input에 직접 내용이 입력될때도, 그냥 키보드를 입력했을때도 이벤트가 실행된다.
#addEvent() {
this.#switchEl.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.bind(this));
}
#onInput() {
this.#inputEl.value = this.#inputEl.value.replace(
/[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/,
""
);
}
#onKeyDown(event) {
this.#inputGropuEl.classList.toggle(
"error",
/[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/.test(event.key)
); // 두번째 인자인 조건이 참일때만 토글
this.#keyboardEl
.querySelector(`[data-code=${event.code}]`)
?.classList.add("active");
}
#onKeyUp(event) {
this.#keyboardEl
.querySelector(`[data-code=${event.code}]`)
?.classList.remove("active");
}
event.code는 어떤 키가 눌려졌는지에 대한 값이고, event.key는 눌려진 키의 값이 무엇인지에 대한 값이다.
html 태그들에는 커스텀 속성으로 data-code 값이 있고, 여기에는 각각의 key code가 적혀있다.
따라서 이 이벤트가 발생한 key code가 html 태그의 data-code의 값과 같은 요소에만 이벤트를 발생하게 한다.
이벤트가 발생한 요소에는 .active class를 추가한다.
이벤트는 두가지로 나뉘어야한다. 키가 눌러질때인 keydown, 눌렀던 키가 떼어질때인 keyup.
특수키에는 이벤트를 할당하지 않을 것인데, OS마다 키가 다르기때문에 에러가 발생할 수 있기 때문이다.
특수키들에는 data-code가 작성되어 있지 않기때문에 예외처리를 해주어야한다.
그래서 위의 코드에서는 ?를 추가하는 옵셔널 체이닝을 사용했다.
💡 옵셔널 체이닝 (?)
프로퍼티가 없는 중첩 객체를 에러 없이 안전하게 접근할 수 있다.
?는 ?앞의 평가 대상이 undefined나 null이면 평가를 멈추고 undefined를 반환한다. 즉, 값이 없을 경우에는 에러를 발생시키지 않고 undefined를 반환하게 된다.
- obj?.prop : obj가 존재할 경우 obj.prop 반환 / 아닐경우 undefined
- obj?.[prop] : obj가 존재할 경우 obj[prop] 반환 / 아닐경우 undefined
- obj?.method() : obj가 존재할 경우 obj.method() 호출 / 아닐경우 undefined
즉, 위의 코드에서는 이벤트가 발생한 요소를 #keyboard에서 찾을 수 있다면 클래스가 추가되거나 삭제되고, 찾을수 없는 경우(특수키) undefined가 리턴되고 이벤트 자체가 실행되지 않는다.
한글 입력시 에러
keydown시 한글이 입력되면 input-group의 에러메시지를 출력하게 한다.
이를 위해서 정규식을 사용하고, 정규식의 test() 메서드를 사용했다.
test() 메서드는 주어진 문자열이 정규 표현식을 만족하는지 판별하고, 그 여부를 true/false로 반환한다.
/[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/.test(event.key)
즉, 이 코드는 event.key가 한글인지 아닌지를 판별하는 코드이다.
toggle 메서드를 사용해서, 두번째 인자인 조건이 참일때만 error 클래스가 토글되도록 작성했다.
또 한글 입력이 될때 에러메시지만 나타나는 것이 아니라 한글은 input에 입력되지 않도록 해야한다.
input이 입력 자체를 막는 것이 아니라, input에 한글이 입력되면 그 값을 빈 문자열로 입력하도록 바꿔준다.
이것은 위에서 사용한 정규식과 replace 메서드를 사용했다.
this 바인딩
document.addEventListener("keydown", this.#onKeyDown.bind(this));
document.addEventListener("keyup", this.#onKeyUp.bind(this));
this.#inputEl.addEventListener("input", this.#onInput.bind(this));
위의 코드를 보면, 이벤트에 .bind(this)가 붙어 있다.
class에서 이벤트를 걸어줄때 this.#onKeyUp 형태로 이벤트를 작성하면 함수 자체로 실행이 된다.
이 인스턴스를 가리키게 하기 위해서 this를 사용했는데 함수가 실행되면 this가 전역객체인 윈도우를 바라보게 되기때문에 해당하는 요소들을 제대로 찾지 못하고 에러가 난다.
그래서 this가 변경되지 않도록 바인딩, 즉 내가 원하는 요소를 계속 바라보도록 고정해주는 것이다.
그래서 .bind() 메서드를 사용해 this가 계속 생성된 인스턴스를 바라보도록 고정시켜주었다.
.
************************
#패스트캠퍼스 #패캠챌린지 #수강료0원챌린지 #환급챌린지 #직장인인강 #직장인자기계발
#패캠인강후기 #패스트캠퍼스후기 #오공완 #30개프로젝트로배우는프론트엔드withReact
본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.
'study > fastcampus' 카테고리의 다른 글
[React] 이미지 슬라이드 - 1. 프로젝트 개요 및 개발환경 설정 (0) | 2023.02.25 |
---|---|
[React] 가상 키보드 만들기 - 5. 마우스 이벤트 작성 (0) | 2023.02.24 |
[React] 가상 키보드 만들기 - 3. Dark theme, font 변경 (0) | 2023.02.22 |
[React] 가상 키보드 만들기 - 2. html, css 작업 (0) | 2023.02.21 |
[React] 가상 키보드 만들기 - 1. 개발환경 설정 (0) | 2023.02.20 |