프로그래밍/Vue.js

Vue.js > 컴포넌트 만들기 > TextInput.vue > 코드 이해하기

에그티비 2024. 12. 4. 23:13
$attrs
v-model = "form.name"
v-bind="{ ...$attrs, class: null}"
modelValue
@input="$emit('update:modelValue', $event.target.value)"

 

 

TextInput.vue (컴포넌트)

<script setup>
import { ref, defineProps, defineEmits } from 'vue'
import { v4 as uuid } from 'uuid'

const props = defineProps({
  id: {
    type: String,
    default: () => `text-input-${uuid()}`,
  },
  type: {
    type: String,
    default: 'text',
  },
  error: String,
  label: String,
  modelValue: String,
  title: String,
})

const emit = defineEmits(['update:modelValue'])
const input = ref(null)

const focus = () => {
  input.value.focus()
}

const select = () => {
  input.value.select()
}

const setSelectionRange = (start, end) => {
  input.value.setSelectionRange(start, end)
}
</script>

<template>
  <div :class="$attrs.class">
    <label v-if="label" class="form-label" :for="id">{{ label }}:</label>
    <input :id="id" ref="input" v-bind="{ ...$attrs, class: null }" class="form-input" :class="{ error: error }" :type="type" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
    <div v-if="error" class="form-error">{{ error }}</div>
    <div>
      {{ $attrs }}
    </div>
  </div>
</template>

 

Parents.vue (부모 컴포넌트)

<script setup>
import TextInput from "./TextInput.vue";
import { useForm } from "@inertiajs/vue3";
import { ref, onMounted } from 'vue';

const form = useForm({
    first_name: '',
});

const textInput = ref(null);

onMounted(() => {
    form.first_name = 'test';
});

const focus = () => {
    textInput.value.$refs.input.focus();
    textInput.value.$refs.input.select();
}

</script>

<template>
    <div>
        <text-input ref="textInput" v-model="form.first_name" :error="form.errors.first_name" class="pb-8 pr-6 w-full lg:w-1/2" label="First name" title="title" content="content" @focus="focus" />
        <button @click="focus()" class="bg-blue-500 text-white p-2 rounded">focus</button>
    </div>
</template>

 

랜더링 결과

 

[코드 분석해 보기]

 

v-bind="{ ...$attrs, class: null }" 의 최종 랜더링 코드는

{ "class": "pb-8 pr-6 w-full lg:w-1/2", "content": "content" } 이다.

 

defineProps 에서 정의된 변수

Id:
type:
error: String,
label: String,
modelValue: String,
title: String,

 

...$attrs 의 데이타는 defineProps 에 선언되지 않는 나머지 모든 속성을 표시해 주는 코드이다. 단 class 속성은 제외 시키는 코드이다.

 

modelValue 에 대해서 알아보자.

v-model 과 양방향으로 바인딩된 미리 설정된 단어다.

 

modelValue 의 데이타는 v-model="form.first_name" 의 form.first_name 과 연결되어 있다.

 

:value="modelValue" 는 modelValue의 데이타가 입력값으로 표시된다.

 

@input="$emit('update:modelValue', $event.target.value)"

입력 박스에 문자를 입력할 때마다, 입력된 데이타가 부모의 데이타와 바인딩된 modelValue 의 데이타를 변경하는 정규화된 이벤트이다.

 

const emit = defineEmits(['update:modelValue']) 정의해 두었지만, 부모 컴포넌트에서는 함수가 미리 선언되어 있지 않다.

 

자식이 부모 데이타를 변경하기 위해서는 emit()를 사용한다. 

 

반대로는 부모가 자식 컴포넌트에 포함된 함수를 실행하기 위해서는 ?

 

ref="" 를 이용한다.

 

textInput.value.$refs.input.focus();

부모ref.value.$refs.자식ref.함수();