v-model의 동작 원리와 활용 방법

들어가며

오랜만에 글을 쓰네요. 오늘은 Vue.js로 Form 요소를 개발할 때 사용하는 v-model 속성에 대해서 살펴보려고 합니다. 이 속성은 그냥 사용하면 그렇게 어렵지 않은데 실제 애플리케이션을 개발할 때는 꽤 주의해서 다뤄야 합니다. 그럼 v-model의 동작 원리와 활용 방법 등에 대해서 알아볼게요!

v-model 속성

공식 문서에 안내된 v-model 속성의 사용법은 아래와 같습니다.

<input v-model="inputText">
new Vue({
  data: {
    inputText: ''
  }
})

이렇게 사용자의 입력을 받는 UI 요소들에 v-model이라는 속성을 사용하면 입력 값이 자동으로 뷰 데이터 속성에 연결됩니다.

v-model

v-model은 어떻게 동작할까?

v-model 속성은 v-bindv-on의 기능의 조합으로 동작합니다. 매번 사용자가 일일이 v-bindv-on 속성을 다 지정해 주지 않아도 좀 더 편하게 개발할 수 있게 고안된 문법인 거죠. 앞에서 살펴본 코드를 아래와 같이 변경하더라도 동일하게 동작합니다.

<input v-bind:value="inputText" v-on:input="updateInput">
new Vue({
  data: {
    inputText: ''
  },
  methods: {
    updateInput: function(event) {
      var updatedText = event.target.value;
      this.inputText = updatedText;
    }
  }
})

위 코드를 이해하기 위해서는 다음 3가지 사실을 알고 있어야 합니다.

  • v-bind 속성은 뷰 인스턴스의 데이터 속성을 해당 HTML 요소에 연결할 때 사용한다.
  • v-on 속성은 해당 HTML 요소의 이벤트를 뷰 인스턴스의 로직과 연결할 때 사용한다.
  • 사용자 이벤트에 의해 실행된 뷰 메서드(methods) 함수의 첫 번째 인자에는 해당 이벤트(event)가 들어온다.

HTML 입력 요소의 종류에 따라 `v-model` 속성이 각각 다음과 같이 구성됩니다.
(1) input 태그에는 `value / input`
(2) checkbox 태그에는 `checked / change`
(3) select 태그에는 `value / change`

그럼 v-model이 더 편하니까 이거 쓰면 되는거죠?

빠르게 기능을 구현하고 프로토타이핑 해나갈 때는 v-model을 사용해도 상관없습니다. 다만, 현재 시점에서는 IME 입력(한국어, 일본어, 중국어)에 대해서 아래와 같은 한계점이 있습니다.

v-model-ime

위 화면을 보면 한글 입력의 경우 한 글자에 대한 입력이 끝나야지만 inputText 데이터가 인풋 박스의 텍스트 값과 동기화됩니다. 아마 조금 전에 살펴봤던 화면을 보면 더 쉽게 비교가 될 겁니다.

v-model

위와 같은 v-model의 한계점 때문에 뷰 공식 문서에서는 한국어 입력을 다룰 때 v-bind:valuev-on:input직접 연결해서 사용하는 것을 권고하고 있습니다.

v-model 문법을 이용해서 한국어를 처리할 순 없을까요?

이렇게 매번 한국어 입력을 처리할 때 v-model 대신에 직접 이벤트와 값을 조합해서 바인딩 하는 것이 귀찮게 느껴질 수 있습니다. 이럴 땐 아래와 같이 인풋 컴포넌트를 별도의 컴포넌트로 분리하면 v-model로 편하게 처리할 수 있습니다.

<!-- BaseInput.vue - 싱글 파일 컴포넌트 구조-->
<template>
  <input v-bind:value="value" v-on:input="updateInput">
</template>

<script>
export default {
  props: ['value'],
  methods: {
    updateInput: function(event) {
      this.$emit('input', event.target.value);
    }
  }
}
</script>

위 코드의 동작을 간단하게 설명하자면 다음과 같습니다.

  • BaseInput 컴포넌트의 상위 컴포넌트에서 props로 받은 value를 인풋 태그에 값으로 연결합니다.
  • 인풋 태그에서 값이 입력되면 인풋 태그에서 input 이벤트가 발생하고 updateInput 메서드가 실행됩니다.
  • updateInput 메서드에서 인풋 태그에 입력된 값을 상위 컴포넌트에 input 이벤트로 올려 보냅니다.

이제 이 컴포넌트를 등록해서 아래와 같이 사용할 수 있습니다.

<!-- App.vue - 싱글 파일 컴포넌트 구조 -->
<template>
  <div>
    <base-input v-model="inputText"></base-input>
  </div>
</template>

<script>
import BaseInput from './BaseInput.vue';

export default {
  components: {
    'base-input': BaseInput
  },
  data: function() {
    return {
      inputText: ''
    }
  }
}
</script>

여기서 주의 깊게 살펴볼 만한 부분은 상위 컴포넌트에서 정의한 데이터 값을 하위 컴포넌트로 내려보내는 부분입니다.

평소에 사용하던 프롭스 속성 대신에 v-model을 사용했는데요. 이미 앞 v-model은 어떻게 동작할까? 챕터에서 v-model 속성은 v-bind:valuev-on:input을 조합해서 만들었다는 것을 배웠기 때문에 v-model 속성에 연결한 값이 하위 컴포넌트에 value 라는 프롭스 속성으로 내려간다는 사실을 추론할 수 있습니다.

마무리

오늘은 v-model의 기본 문법과 내부 동작 원리 그리고 한국어 입력을 좀 더 효율적으로 처리하는 방법에 대해서 알아보았습니다. 아무래도 이 글을 읽으시는 분들 중에 국내 사용자를 대상으로 웹 서비스를 제작하시는 분들이 많을 테니까요. 아무쪼록 제 글이 이분들께 도움이 되었으면 좋겠네요 😄

그럼 재밌게 코딩하시고 또 다음에 뵙겠습니다~!

글보다 더 쉽게 배우는 온라인 강좌

좀 더 친절하고 상세한 설명을 원하신다면 아래 강좌를 이용해보시는 것도 좋을 것 같아요 😄

인프런 온라인 강의 : Vue.js 시작하기, Vue.js 중급, Vue.js 완벽 가이드
인프런 온라인 강의 : Vue.js 끝장내기, 쉽게 배우는 Webpack, PWA 시작하기