-
[JS] input 태그에 한글 입력 막기programing/Language 2020. 8. 2. 22:39
안녕하세요, Einere입니다.
(광고 차단 기능을 꺼주시면 감사하겠습니다.)
움짤이 버벅거리거나 잘 보이지 않는다면 클릭해주세요.
요구사항
프로젝트에서 특정 input창에 왼쪽 방향키, 오른쪽 방향키, 백스페이스를 제외한 문자가 입력되는 것을 방지해야 했습니다.
저는 '음.. 조금 귀찮긴 하겠지만 할만하네' 라고 생각했습니다. 하지만 이때의 저는 험난한 여정이 시작될 것을 몰랐습니다..
첫 구현
inputElement.addEventListener("keydown", function handleKeyDown(e) { console.log("key down", e.key, e.code); const whiteList = ['ArrowLeft', 'ArrowRight', 'Backspace']; if (!whiteList.some(code => e.code === code)) { e.preventDefault(); return; } if (e.code === 'Backspace') { e.preventDefault(); return; } }
whitelist
와e.code
를 이용해, 왼쪽 화살표, 오른쪽 화살표, 백스페이스를 제외한 키는 입력을 방지하도록 해보겠습니다.한글 빼고는 잘 막아집니다. 그럼 한글 입력 방지는 어떻게 해야 할까요?
정규표현식과 preventDefault()를 이용해보자
일단 요구사항은 허용된 키 이외에는 모두 입력을 막아야 합니다. 영어는 잘 막아지니까, 영어가 아닌 것들은 싹 다 쳐내도록 해보겠습니다.
inputElement.addEventListener("keydown", function handleKeyDown(e) { console.log("key down", e.key, e.code); const notEngExp = /[^A-Za-z]/g; const isNotEng = notEngExp.test(e.key); if (isNotEng) { console.log("not english"); e.preventDefault(); return; } }
위 코드로, 영어가 아닌 키 입력이 잘 막아지는지 테스트 해보겠습니다.
정규표현식은 잘 되지만 여전히 `preventDefault()` 로 한글 입력 방지는 안됩니다. 🤔
구글링을 하다 보니, 한글은 조합글자라서 keypress로 핸들링해야 한다는 글이 있었습니다. 그렇다면, 다음 코드로 테스트를 해봅시다.
inputElement.addEventListener("keypress", function handleKeyPress(e) { console.log("key press", e.key, e.code); const whiteList = ["ArrowLeft", "ArrowRight", "Backspace"]; const notEngExp = /[^A-Za-z]/g; const allowedKey = whiteList.some((code) => e.code === code); const isNotEng = notEngExp.test(e.key); if (!allowedKey) { console.log("not allowed"); e.preventDefault(); return; } if (e.code === "Backspace") { e.preventDefault(); return; } if (isNotEng) { console.log("not english"); e.preventDefault(); return; } }
backspace는 콘솔에 출력되는게 아무것도 없는 것으로 보아, non character 문자들은 keypress 이벤트에 걸리지도 않는 것 같습니다.
한글도 콘솔에 찍히는게 없는 것으로 봐서는 이벤트에 걸리진 않지만, 그렇다고 입력이 방지되지는 않았습니다.
정규 표현식과 replace()를 이용한 방법
inputElement.addEventListener("keyup", function (e) { console.log("key up", e.key, e.code); const whiteList = ["ArrowLeft", "ArrowRight", "Backspace"]; const notEngExp = /[^A-Za-z]/g; const allowedKey = whiteList.some((code) => e.code === code); const isNotEng = notEngExp.test(e.key); const koreanExp = /[ㄱ-ㅎㅏ-ㅣ가-힣]/g; // if (!allowedKey) { // console.log("not allowed"); // e.preventDefault(); // return; // } // if (e.code === "Backspace") { // e.preventDefault(); // return; // } if (isNotEng) { console.log("not english"); e.preventDefault(); e.target.value = e.target.value.replace(koreanExp, ""); return; } });
keyup 이벤트 핸들러를 정의해줍니다.
음.. 엄밀히 말하면 막는 게 아니라 지우는거긴 합니다. UX도 구리구요.. 😵
W3 명세에 따르면
W3의 명세의 Canceling Composition Events 섹션을 보면, keydown 이벤트가 캔슬되면 keydown 이벤트의 결과로 인해 발생할 수 있는 모든 composition event는 dispatch되지 않아야 한다고 합니다.
즉, input 요소에 @keydown.prevent만 해줘도 모든 컴포지션 이벤트를 막을 수 있다는 것이죠. 그러나 code sandbox를 통해 실험한 결과, 컴포지션 이벤트들이 아주 잘 dispatch 되었습니다.
아마 명세를 따르지 않았거나, 한글만 예외적이거나.. 라고 생각합니다.
그런데.. 명세를 조금 더 읽어보니, compositionstart 이벤트 섹션에 다음과 같은 글이 쓰여져 있었습니다.
Some IMEs do not support cancelling an in-progress composition session (e.g., such as GTK which doesn’t presently have such an API). In these cases, calling preventDefault() will not stop this event’s default action.
헉.. 몇몇 IMEInput Method Editor는 진행중인 컴포지션 세션을 종료하는 것을 지원하지 않으며, 이 경우
preventDefault()
로 해당 이밴트의 기본 액션을 멈출 수 없다고 합니다. 😰완벽하진 않지만 막을 수 있어
조금 더 찾아보니 compositionstart 이벤트 핸들러에서, 다음과 같이 한글(조합 문자) 입력을 방지할 수 있긴 합니다.
composition event를 포함한 input 요소의 이벤트들에 대한 더 자세한 정보는 [JS] input element event 를 참고해주세요!
inputElement.addEventListener("keydown", function keyDownHandler (e) { console.log("key down", e.key, e.code); const whiteList = ["ArrowLeft", "ArrowRight", "Backspace"]; const allowedKey = whiteList.some((code) => e.code === code); if (!allowedKey) { console.log("not allowed"); e.preventDefault(); return; } if (e.code === "Backspace") { e.preventDefault(); return; } }); inputElement.addEventListener( "compositionstart", function handleCompositionStart(e) { const self = this; self.blur(); requestAnimationFrame(function () { self.focus(); }); } ); const button = document.getElementById("check"); const span = document.getElementById("span"); button.addEventListener("click", function clickHandler(e) { span.textContent = inputElement.value; });
물론 광클하면 못막긴 합니다만.. 나름 막을 수는 있네요..
'programing > Language' 카테고리의 다른 글
deep copy (0) 2020.08.27 [JS] input element event (0) 2020.08.08 [ESLint, Airbnb] import/extensions 규칙 설정하기 (0) 2020.06.28 [LokiJS] 나의 삽질 후기 (0) 2020.05.21 [React] 함수형 컴포넌트와 훅 (0) 2020.05.18 댓글