인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

bestksw님의 프로필 이미지
bestksw

작성한 질문수

퀘이사(Quasar) 완벽 마스터: Vue 프론트 웹을 빠르게 만들고 싶다면! (Based Vue3)

한글 실시간 바인딩

해결된 질문

작성

·

2.1K

·

수정됨

2

vue에서는 한글 실시간 바인딩을 다음 코드로 합니다.

 

<template> <h1>{{ msg }}</h1>

<input type="text" :value="msg" @input="msg = $event.target.value" />

</template>

 

하지만 퀘이사의 q-input에서는 @input 이벤트가 디프리케이트 되어서 동작하지 않습니다.

한글 실시간 처리를 하려면 어떻게 해야할지요?

감사합니다.

 

 

답변 2

1

짐코딩님의 프로필 이미지
짐코딩
지식공유자

안녕하세요 :)

<q-input v-model="msg" /> 

또는

<q-input
    :model-value="msg"
    @update:model-value="value => (msg = value)"
/>

아래 링크를 참고하시면 이해하는데 도움이 되실거에요 :)

bestksw님의 프로필 이미지
bestksw
질문자

답변 감사합니다.

동일한 방식대로 했을때 아래 블로그처럼 실시간 한글 바인딩이 되지 않습니다.ㅠ

https://webruden.tistory.com/485

 

제가 디프리케이드 안된 @keyup 방식으로도 해봤지만 한글이 깨집니다. (예를들면 "대구"로 타이핑 하지만 변수에는 "댁구")

@input을 사용해야 할꺼 같은데 방법이 없을까요?

GPT에도 질의해봤지만 @input방식만 알려줍니다.

짐코딩님의 프로필 이미지
짐코딩
지식공유자

양방향 바인딩은 v-model 를 사용하는게 맞는데용 🤔

키보드 이벤트 처리를 하고 싶은데 한글이 정상동작을 안해서 문제가 되는걸까요?

그렇다면 @keypress 로 해보시겠어요?

bestksw님의 프로필 이미지
bestksw
질문자

<q-input
  :value="modelval"
  @keypress="evt => (modelval = evt.target.value)"
>

위 코드로 해봤지만 증상은 더 심각하게 업뎃조차 안되며 엔터쳐야 업뎃됩니다. (기존 v-model을 활용하면 커서가 옮겨지면 업뎃은 되었습니다.)

실제 개발은 아래 링크의 autocomplete를 구현하기 위한 q-select를 활용하고 있어서 문의드렸습니다.

https://quasar.dev/vue-components/select#native-attributes-with-use-input

기능 구현이 잘 안되서 현재는 그냥 hint에 엔터를 눌러달라는 안내문구만 추가하였습니다.

답변 감사합니다!

짐코딩님의 프로필 이미지
짐코딩
지식공유자

@keypress를 말씀 드린건 키보드 이벤트 활용시 한글 이슈가 있으면 해보시라고 말씀드린거고요.

코드 전체를 보여주실 수 있으신가요?

setup 함수내에서 반응형 상태(const msg = ref(''))를 선언하고

v-model에서 잘 사용하셨으면 문제가 없어보이는데요.

bestksw님의 프로필 이미지
bestksw
질문자

<template>
  <div class="q-pa-md">
    <div class="q-gutter-md">
      <q-select
        filled
        v-model="model"
        clearable
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        label="Focus after filtering"
        :options="options"
        @filter="filterFn"
        @filter-abort="abortFilterFn"
        style="width: 250px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey"> No results </q-item-section>
          </q-item>
        </template>
      </q-select>

      <q-select
        filled
        v-model="model"
        clearable
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        label="Autoselect after filtering"
        :options="options"
        @filter="filterFnAutoselect"
        @filter-abort="abortFilterFn"
        style="width: 250px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey"> No results </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>

<script>
import { ref } from 'vue';

const stringOptions = ['가나다', '마바사', '아자차', '테스트', '헤이루'].reduce(
  (acc, opt) => {
    for (let i = 1; i <= 5; i++) {
      acc.push(opt + ' ' + i);
    }
    return acc;
  },
  [],
);

export default {
  setup() {
    const options = ref(stringOptions);

    return {
      model: ref(null),
      options,

      filterFn(val, update, abort) {
        // call abort() at any time if you can't retrieve data somehow

        setTimeout(() => {
          update(
            () => {
              if (val === '') {
                options.value = stringOptions;
              } else {
                const needle = val.toLowerCase();
                options.value = stringOptions.filter(
                  v => v.toLowerCase().indexOf(needle) > -1,
                );
              }
            },

            // "ref" is the Vue reference to the QSelect
            ref => {
              if (val !== '' && ref.options.length > 0) {
                ref.setOptionIndex(-1); // reset optionIndex in case there is something selected
                ref.moveOptionSelection(1, true); // focus the first selectable option and do not update the input-value
              }
            },
          );
        }, 300);
      },

      filterFnAutoselect(val, update, abort) {
        // call abort() at any time if you can't retrieve data somehow

        setTimeout(() => {
          update(
            () => {
              if (val === '') {
                options.value = stringOptions;
              } else {
                const needle = val.toLowerCase();
                options.value = stringOptions.filter(
                  v => v.toLowerCase().indexOf(needle) > -1,
                );
              }
            },

            // "ref" is the Vue reference to the QSelect
            ref => {
              if (
                val !== '' &&
                ref.options.length > 0 &&
                ref.getOptionIndex() === -1
              ) {
                ref.moveOptionSelection(1, true); // focus the first selectable option and do not update the input-value
                ref.toggleOption(ref.options[ref.optionIndex], true); // toggle the focused option
              }
            },
          );
        }, 300);
      },

      abortFilterFn() {
        // console.log('delayed filter aborted')
      },
    };
  },
};
</script>

퀘이사 공식 홈페이지에서 autocomplete 예시를 가져와서 옵션값을 한글로만 바꾸었습니다.

테스트 글자를 입력해 보시면 테스트 끝까지 칠때까지 autocomplete가 동작하지 않습니다.
참고로 영어는 잘 됩니다.. 한글만 잘 안됩니다!ㅠ

귀중한 시간 내 주셔서 감사드립니다!

짐코딩님의 프로필 이미지
짐코딩
지식공유자

우선 위 코드에서 v-model="model" 값은 옵션(option)이 선택되었을때 변경되는게 맞겠죠?

그런데 한글 이슈가 있으신것 같은데요 🤔
(이벤트 처리에서 한글 이슈는 종종 생겨서요.)

처음에 질문하신 내용이랑은 다른 내용같은데요.

  • 우선 선언되어있는 함수(filterFn, filterFnAutoselect)를 디버깅 해보셔야 할 거 같아요.

  • 아니면 QSelect API에서 Events 탭을 보셔서 다른 이벤트로 처리할 수 있는지 확인 🥲

그리고 참고로 문제가 있는 부분을 찾고 해결하실때는 최대한 간결한코드로 하면 더 좋을 거 같아요~!

 

 

bestksw님의 프로필 이미지
bestksw
질문자

디버깅도 시도 해 보았고 기재되어 있는 모든 이벤트에 대하여 테스트를 해보았는데 결국 적절한 해결책을 찾지 못해 질문을 드려 봤습니다.

 한글 이슈가 조금 아쉽긴 하네요.ㅠㅠ 귀중한 시간 내 주셔서 감사드립니다!

 ps. 위 예제는 공식 홈페이지 예제이며 옵션만 한글로 변경하였습니다. 공식 홈페이지 예제가 가장 잘 짜여진 코드이니 축소없이 올려드린점 양해 부탁 드립니다!

짐코딩님의 프로필 이미지
짐코딩
지식공유자

<template>
  <q-select ref="qSelectRef" use-input> </q-select>
</template>

<script>
import { onMounted, ref } from 'vue';

export default {
  setup() {
    const qSelectRef = ref(null);
    onMounted(() => {
      qSelectRef.value.$el
        .querySelector('input')
        .addEventListener('input', function (e) {
          console.log(e.target.value);
        });
    });
    return {
      qSelectRef,
    };
  },
};
</script>

Template Refs를 활용하여 Native Element($el) 를 가져오신 후 addEventListener 를 활용하시면 이슈가 해결될 거 같은데요?

한번 해보시겠어요?

bestksw님의 프로필 이미지
bestksw
질문자

해당 코드로 이것저것 tricky하게 건드려서 autocomplete q-select 성공했습니다!

선생님과 수강생분들께도 참고하시라 코드 공유 드립니다.

귀중한 시간 내어주셔서 감사합니다.

<template>
  <div class="q-pa-md">
    <div class="row q-gutter-md">
      <q-select
        filled
        clearable
        use-input
        hide-selected
        fill-input
        ref="qSelectRef"
        v-model="modeldummy"
        :value="model"
        :options="options"
        style="width: 250px"
        @input-value="updateVal"
      >
      </q-select>
      <p>Text: {{ model }}</p>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';

const stringOptions = ['가나다', '마바사', '아자차', '테스트', 'google'].reduce(
  (acc, opt) => {
    for (let i = 1; i <= 5; i++) {
      acc.push(opt + ' ' + i);
    }
    return acc;
  },
  [],
);
const options = ref(stringOptions);

const qSelectRef = ref(null);
const model = ref(null);
const modeldummy = ref(null);

onMounted(() => {
  qSelectRef.value.$el
    .querySelector('input')
    .addEventListener('input', function (e) {
      console.log(e.target.value);
      model.value = e.target.value;

      if (model.value === '') {
        options.value = stringOptions;
      } else {
        const needle = model.value.toLowerCase();
        options.value = stringOptions.filter(
          v => v.toLowerCase().indexOf(needle) > -1,
        );
        console.log('options', options.value);
      }

      if (
        model.value !== '' &&
        qSelectRef.value.options.length > 0 &&
        qSelectRef.value.getOptionIndex() === -1
      ) {
        qSelectRef.value.moveOptionSelection(1, true); // focus the first selectable option and do not update the input-value
        qSelectRef.value.toggleOption(
          qSelectRef.value.options[qSelectRef.value.optionIndex],
          true,
        ); // toggle the focused option
      }
    });
});

const updateVal = val => {
  model.value = val;
};
</script>

 

짐코딩님의 프로필 이미지
짐코딩
지식공유자

와우 축하드려요!🎉 ㅎㅎ
공유 감사요! 👍

0

### Quasar Input 한글 IME 이슈

이미 해결하신 질문이지만, 공유차원에 내용을 추가합니다.

### 개발환경
- 맥, 크롬 , 사파리
- quasar : 2.6.0
- vue : 3.0.0

### 증상
- Vue3에서 해결됬다는 한글 input IME 이슈가 Quasar q-input 에서 발생
image
- 강사님께서 제시하신 방법 적용해봤으나, 전부 오동작(@update:model-value, @keypress)

### 해결방법
- q-input tag에 ref를 먹여 onMount 시 해당 태그에서 리스너를 등록하여 상태를 갱신

<q-input
                  ref="qInputRef"
                  dense
                  color="primary"
                  label="searchKeyword"
                  :model-value="searchKeyword"
                >
                </q-input>


onMounted(() => {
  console.log('onMounted');

  const el = qInputRef.value.getNativeElement();
  el.addEventListener('input', e => {
    console.log('input', e.target.value);
    searchKeyword.value = e.target.value;
  });

  initPage();
});


react를 조금 해본 입장에서, 좀 편하게 쓸려고 vue Quasar를 써볼까 했는데... 이런 기본적인게 안되니 안타깝네요.


### 문제해결 참고자료
https://stove99.github.io/javascript/2021/06/29/quasar-v2-q-input-ime/

bestksw님의 프로필 이미지
bestksw

작성한 질문수

질문하기