뚝딱뚝딱

vuetify v-text-field 혹은 vuejs input 에서 한글 입력 막기

산도야지 2019. 2. 21. 22:36

아 이것으로 2:29 동안 삽질을 했더니 진이 빠진다. 밀린 작업좀 처리하려고 했는데 이게 뭐냐.

이벤트에 탐지되지 않는 한글 문자

  1. 크롬에서
  • keypress 이벤트.
    • event : KeyboardEvent
    • event.key : 아무것도 안 잡힘
    • event.target.value : 아무것도 안 잡힘

keypress 는 인쇄가능한 글자만 잡는다. 그래서 화살표, 백스페이스, 딜리트 키 등이 안 잡힘. 참조-모질라 keypress 문서

  • keydown 이벤트.
    • event : KeyboardEvent
    • event.key : "Process" 라고 나옴
    • event.target.value : 지금 입력한 key 이전까지 모든 글자내용
  1. 파이어폭스에서

크롬과 다르게 동작함. 참조-스택오버플로우

  1. IE 에서는?

생각도 하기 싫다.

Process 로 검출한다고 해도 한글이 통과되어 버린다.

모든 브라우저가 아니더라도 어찌 크롬만에서라도 되게 해보려고 다음처럼 막아보자.

if(ev.key === "Process"){
  ev.preventDefault();
}

근데, 영문, 숫자, 특문 다 먹히는데 한글만 통과되어 버린다. 미치고 팔짝 뛴다.

이게 조합하는 문자라 Process 라고(추측) 떨어지나? 그럼 뭔가 이것만 통과 되어버리나 싶어 찾아보니 다음과 같이 옵션을 주면 아예 한글입력을 막는다.

<input style="ime-mode:disabled">

요렇게 하면 ime(조합) 키보드 모드를 비활성화 한다. 그래서 입력도 안 됐는데 에 밑줄 붙은 식으로 인풋 입력을 우회할 수 없어 한글입력이 안 된다고 카더라.

인스웨이브에서 브라우저 별로 어떤 방법이 먹히는 지 잘 정리해 주었다.

IE와 FF는 ime-mode 속성을 이용하여 한글입력을 제한할 수 있다
chrome과 safari는 onkeyup 이벤트에서 charCode값을 이용하여 입력된 한글을 지울 수 있다
opera는 위 1,2번 방법 모두 불가능하다
위 2번 방법은 IE와 FF에서 유효하지 않다

일반적인 html input 에서 한글 입력 막기

아래 둘을 참조.

vue.js 에서 input 을 사용하면 위 방법 다 먹힌다.

vuetify 의 v-text-field 에서 한글 입력 막기

v-text-fieldinput 의 래퍼라서, 거기다가 style 줘 봤자 안 먹힌다.

셀렉터를 써봤는데, 안먹히네, 왜 그런지 까지 시간상 확인할 수가 없다.

이거 정리하고 바로 퇴근할거니까. 지금 저녁 10시 22분이다.

결론 빨리!! 타입스크립트용이다.

<template>
  <v-text-field :value="email"
                :label="라벨라벨"
                @input="filteringHandler"
                ref="formRef">
  </v-text-field>
</template>

<script lang="ts">
  import ...

  @Component({
    name: 'Example',
  })

  /**
     * 한글입력 막기위한 예시 컴포넌트다.
     * @class Example
     * */
  export default class Example extends Vue {

    /** 입력 필터 - 한글만 */
    public REG_FILTER_KOREAN_LETTER:RegExp = /[^ㄱ-ㅎㅏ-ㅣ가-힣]*/i;

    private filteringHandler(str: string) {
      console.log(str);

      // 이메일 관련 문자열만 추출, i 옵션때문에 0 번째 인덱스로 추출된다.
      const email = extractedMail = str.match(REG_FILTER_KOREAN_LETTER)[0];

      // 타입이 VTextField 이지만, import 해도 Cannot find name 'VTextField'. 오류가 나서 any 타입 할당        

      const field: any = this.$refs.formRef as any;
      // 내부 input 필드가 아닌, v-text-field 의 내부 변수를 직접 바꾼다.
      field.lazyValue = email;
    };
  }
}
  1. 반드시 :value 로 바인딩 해야한다.

v-model 은 양방향 바인딩이라서.. 입력 값을 자기가 벌써 원본 모델에 업데이트를 해버린다.

<input v-model="변수">

면,

<input
   v-bind:value="변수"
   v-on:input="변수 = $event.target.value"
>

혹은

<input
   :value="변수"
   @input="변수 = $event.target.value"
>

와 같은데(참조), 그런 상황에서 input 이벤트를 쓰면 input 이벤트가 연쇄적으로 두번 걸려서, 폼 필드보면 같은 글자가 두개씩 쳐지고 없어지고 난리 부르스를 춘다.

근데

<input
   :value="something"
   @input="something = $event.target.value"
>

위처럼 하고, @input 을 걸고, 내가 직접 업데이트 하는 것으로 처리하면, 입력된 것을 가로채서 깔끔하게 한 번에 넣을 수 있다.

  1. 반드시 lazyvalue 를 ref 로 직접 변경해야 한다.

내부 input 요소에 값을 입력하면, 내부 input 요소에서 발생한 @input 이벤트가 버블링 업 되어서 최종 부모인 v-text-field@input 이벤트가 발생한다.

input 이벤트가 두 개, 거의 동시에 발생하고, 그 찰나의 순간에 내부에서 바인딩된 필드를 누가 먼저, 어떤 방식으로 업데이트 하나 알 수가 없다. (귀찮아서 v-text-field 내부까지 안 봤다.)

그 과정을 내가 제어할 수 없으므로, 가로챈 다음에 과정을 건너 뛰고 최종 결과를 보여주는 필드에 바로 할당해 버리는 것으로 내가 제어하는 것.

야근많이 하니 몸이 삭아서 아프고 점점 생각없이 복붙하게 된다.

아, 버스 끊겼나. 지금 10시 35분인데.

v-model 이 편해서 줄창 이것만 쓰다 보면 꼭 무언가 안 되는 경우가 발생하면 그 때는 value 로 하면 해결될 때가 많은데. 쩝. 매번 생각하면서 코딩하기가 쉽지 않네. 일정은 정해져 있고 양은 많고.

코드 정리 이야기가 나와서 하는 중인데, 힘이 부친다.