[Vue3] 컴포넌트 v-model

Dohee Kang·2023년 3월 4일
0

Vue

목록 보기
19/28
post-custom-banner

  • 컴포넌트에서 v-model 디렉티브를 사용하기 위해선 2가지 작업을 수행해야 한다.
  • <CustomInput> 예시로 작성해보자면,
    • 네이티브 <input> 엘리먼트의 value 속성을 modelValue 프로퍼티에 바인딩한다.
    • 네이티브 input 이벤트가 트리거되면 새로운 값으로 update:modelValue 사용자 지정 이벤트를 내보낸다.
  • 실제 작동하는 코드는 아래와 같다.
<!-- CustomInput.vue -->
<template>
  <input
    type="text"
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

<script>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue']
}
</script>
  • 이제 v-model 이 부모 컴포넌트에서 완벽하게 동작한다.
<template>
  <CustomInput v-model="message" />
  <p>{{ message }}</p>
</template>

<script>
import CustomInput from './components/CustomInput.vue';

export default {
  components: {
    CustomInput
  },
  data() {
    return {
      message: ''
    }
  }
}
</script>

1. v-model Arguments

  • 컴포넌트의 v-modelmodelValue를 프로퍼티로, update:modelValue를 이벤트로 사용한다.
  • v-model에 인자를 전달하여 이러한 이름을 수정할 수 있다.
<CustomInput v-model:message="message" />
  • <CustomInput> 에서 props명과 이벤트명을 변경해줘야 한다.
<template>
  <input
    type="text" 
    :value="message" 
    @input="$emit('update:message', $event.target.value)"
  />
</template>

<script>
export default {
  props: ['message'],
  emits: ['update:message']
}
</script>

2. v-model 멀티 바인딩

  • 단일 컴포넌트 인스턴스에서 여러 개의 v-model 바인딩을 생성할 수 있다.
  • v-model은 컴포넌트에서 추가 옵션 없이도 다른 prop에 동기화된다.
<!-- App.vue -->
<template>
  <UserName 
    v-model:firstName="firstName"
    v-model:lastName="lastName"
  />
  <h4>{{ firstName }} {{ lastName }}</h4>
</template>

<script>
import UserName from './components/UserName.vue';

export default {
  ...
  data() {
    return {
      firstName: 'Dohee',
      lastName: 'Kang'
    }
  }
}
</script>

<!-- UserName.vue -->
<template>
  <input
    type="text"
    :value="firstName"
    @input="$emit('update:firstName', $event.target.value)"
  />
  <input
    type="text"
    :value="lastName"
    @input="$emit('update:lastName', $event.target.value)"
  />
</template>

<script>
export default {
  props: ['firstName', 'lastName'],
  emits: ['update:firstName', 'update:lastName']
}
</script>

3. v-model Modifier

  • Form 입력 바인딩에서 modifier가 있듯이 컴포넌트 v-model에도 사용자 정의 modifier가 있다.
  • 아래 예제는 문자열의 첫 글자를 대문자로 표시하는 v-model.capitalize modifier이다.
<UserName v-model.capitalize="firstName" />
  • v-model에 추가되는 modifier는 modelModifiers 프로퍼티를 통해 컴포넌트에 제공한다.
  • 아래 예제는 빈 객체로 설정된 modelModifiers 프로퍼티를 포함하는 컴포넌트이다.
  • this.modelModifiers
    • 컴포넌트 modelModifiers 프로퍼티에 capitalize가 포함되어 있고 그 값은 v-model.capitalize="firstName"에 설정되어 있어 true가 출력된다.
<!-- UserName.vue -->
<template>
  <input
    type="text"
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  created() {
    console.log(this.modelModifiers); // { capitalize: true }
  }
}
</script>
  • @input을 통해 emitValue 메서드가 실행되고 첫 글자를 대문자로 변경한 capitalizeValthis.$emit을 통해 업데이트한다.
<!-- UserName.vue -->
<template>
  <input
    type="text"
    :value="modelValue"
    @input="emitValue"
  />
</template>

<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  methods: {
    emitValue(event) {
      let capitalizeVal = '';
      const value = event.target.value;
      if (this.modelModifiers.capitalize) {
        capitalizeVal = value.charAt(0).toUpperCase() + value.slice(1);
      }
      this.$emit('update:modelValue', capitalizeVal);
    }
  }
}
</script>

4. v-model Arguments와 Modifier 동시 작성 방법

  • value : modelValue -> firstName
  • modifier : modelModifiers -> firstNameModifiers
  • emits : update:modelValue -> update:firstName
<!-- App.vue -->
<UserName v-model:firstName.capitalize="firstName" />

<!-- UserName.vue -->
<template>
  <input
    type="text"
    :value="firstName"
    @input="emitValue"
  />
</template>

<script>
export default {
  props: ['firstName', 'firstNameModifiers'],
  emits: ['update:firstName'],
  created() {
    console.log(this.firstNameModifiers)
  },
  methods: {
    emitValue(event) {
      let capitalizeVal = '';
      const value = event.target.value;
      if (this.firstNameModifiers.capitalize) {
        capitalizeVal = value.charAt(0).toUpperCase() + value.slice(1);
      }
      this.$emit('update:firstName', capitalizeVal);
    }
  }
}
</script>
profile
오늘은 나에게 어떤 일이 생길까 ✨
post-custom-banner

0개의 댓글