TechScribe Notes

18_Event(Emit) 본문

project/Vue.js

18_Event(Emit)

yunmee0704 2024. 12. 24. 12:02

1.Event :

자식 컴포넌트에서 부모 컴포넌트로 데이터 전달 또는 트리거의 목적으로 이벤트를 내보내는 것.

이벤트는 emit메서드를 통해 발생시킬 수 있음

 

2. 이벤트 발생 및 수신 

: templete안에서 내장함수 $emit()을 사용하여 직접 커스텀한 이벤트를 내보낼 수 있음

<!--자식컴포넌트-->

<template>
	<button @click="$emit('someEvent')">버튼</button>
</template>

<!--부모컴포넌트에서 v-on이나 @을 사용해서 이벤트를 수신한다.-->
<MyComponent @some-event="callFunction" />

<!--once도 사용 가능-->
<MyComponent @some-event.once="callFunction" />

 

 

3.이벤트 파라미터

: 이벤트와 함께 특정 값을 내보낼 수 있음. $emit함수 이벤트 명에 추가로 파라미터를 넘길 수 있다.

<!--- 자식 컴포넌트 --->
<template>
	<button @click="$emit('someEvent', 'Hello', 'World', '!')">버튼</button>
</template>


<!--- 부모 컴포넌트 --->
<template>
	<MyComponent @some-event="callFunction" />
</template>

<script setup>
export default {
	setup() {
    //부모 컴포넌트에서 파라미터를 받음
		const callFunction = (word1, word2, word3) => {
      alert(word1, word2, word3);
    };
		return {
			callFunction
		}
	}
}
</script>

 

 

4. 이벤트 선언

emit옵션으로 선언하며 JS코드에서 이벤트를 내보낼 때는 setup()함수 파라미터로 넘어온 context.emit()메서드를 사용할 수 있음.

 

1) 문자열 배열 선언

//context.emit() 사용
export default {
  emits: ['someEvent'],
  setup(props, context) {
    context.emit('someEvent', 'Hello World!')
  }
}


//emit을 객체로 가져옴 (구조분해할당)
export default {
  emits: ['someEvent'],
  setup(props, { emit }) {
    emit('someEvent', 'Hello World!')
  }
}

 

2)객체문법 선언

: validation 로직추가로 유효성 체크 가능. validation없으면 null로 설정.

export default {
  emits: {
		// 유효성 검사가 없는 이벤트 선언
		someEvent: null,

		// 유효성 검사가 있는 이벤트 선언
		someSubmit: (result) => {
			if (email && password) {
	      return true
	    } else {
	      console.warn('result 값이 비어있습니다!')
	      return false
	    }
		}
	},
  setup(props, context) {
    context.emit('someEvent', 'Hello World!')
  }
}

*컴포넌트가 작동하는 방식을 더 문서화하기 위해 모든 이벤트를 정의하는 것이 좋음(선택사항). 그리고 non-prop속성의 리스너 제외 가능.

 

5. v-model만들기

:컴포넌트 생성 후 해당 컴포넌트에 v-model을 적용하려면 @update:modelValue이벤트를 사용하여 만들 수 있음.

<input v-model="username" />

<--- v-model 작동 --!>
<input
  :value="username"
  @input="username = $event.target.value"
/>

<-- 컴포넌트 수행 --!>
<LabelInput
	:modelValue="username"
	@update:modelValue="newValue => username = newValue"
/>

 

 

이 컴포넌트 <LabelInput>이 제대로 동작하게 하려면 컴포넌트를 정의 해야함

- modelValue propsfmf :value 속성에 바인딩

-@input이벤트에서 새 @update:modelValue이벤트로 내보냄

<template>
  <label>
    {{ label }}
    <input
      type="text"
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    />
  </label>
</template>
<script>
export default {
  props: ['modelValue', 'label'],
  emits: ['update:modelValue'],
};
</script>

 

그리고 컴포넌트에 v-model 적용

<LabelInput label="이름" v-model="username" />

 

 

6. Computed 이용해서 v-model구현하기

<template>
  <label>
    {{ label }}
    <input type="text" v-model="value" />
  </label>
</template>
<script>
import { computed } from 'vue';

export default {
  props: ['modelValue', 'label'],
  emits: ['update:modelValue'],
  setup(props, context) {
    const value = computed({
      get() {
        return props.modelValue;
      },
      set(value) {
        context.emit('update:modelValue', value);
      },
    });
    return {
      value,
    };
  },
};
</script>

 

-부모 컴포넌트에 다시 데이터나 이벤트를 전달해야할 때 부모 컴포넌트에서는 v-on(@)디렉티브를 사용하여 전달받은 이벤트를 수신할 수 있음. 아래에서는 @enlarge-text로 이벤트를 받아서 postFontSize값을 업데이트하여 폰트크기를 확대하는 기능을 만듬

-이 때 자식 컴포넌트에서는 emits옵션으로 이벤트를 선언하고 $emit 내장 메서드를 호출하여 이벤트를 발생시킬 수 있음.

 

<-- 1. font사이즈를 반응형으로 선언 --!>
const postFontSize = ref(1);

<-- 2. font사이즈를 반영할 수 있도록 부모 컴포넌트 생성 --!>
<div :style="{ fontSize: postFontSize + 'em' }">
  <BlogPost
    v-for="post in posts"
    :key="post.id"
    :title="post.title"
    @enlarge-text="postFontSize += 0.1"
  />
</div>

<-- 3. 자식 컴포넌트에서 폰트 크기 변경하는 버튼 추가 --!>
<template>
  <article>
    <h4>{{ title }}</h4>
    <button @click="$emit('enlarge-text')">크게</button>
  </article>
</template>

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

export default {
  props: ['title'],
  emits: ['enlarge-text'],
  setup(props) {
    const { title } = toRefs(props);
    return {
      title,
    };
  },
};
</script>

<style></style>

 

 

7. v-model 전달 인자

:v-model은 컴포넌트에서 modelValue props와 update:modelValue 이벤트로 사용함. 그리고 전달인자로 이런 이름을 수정할  수 있음.

 

<BookComponent v-model:title="bookTitle" />

<--- 자식 컴포넌트에서 :title 속성으로 정의하고 update:title로 이벤트를 내보냄--!>
<template>
  <article>
    <strong>책 이름</strong> :
    <input
      type="text"
      :value="title"
      @input="$emit('update:title', $event.target.value)"
    />
  </article>
</template>
<script>
export default {
  props: ['title'],
  emits: ['update:title'],
};
</script>

 

 

8. 다중 v-model 바인딩 

: 전달인자로 컴포넌트에 여러 v-model을 바인딩 할 수 있음.

<BookComponent
	v-model:title="bookTitle"
	v-model:author="bookAuthor"
/>

<template>
  <article>
    <strong>도서명</strong> :
    <input
      type="text"
      :value="title"
      @input="$emit('update:title', $event.target.value)"
    />
    <br />
    <strong>저자</strong> :
    <input
      type="text"
      :value="author"
      @input="$emit('update:author', $event.target.value)"
    />
  </article>
</template>
<script>
export default {
  props: ['title', 'author'],
  emits: ['update:title', 'update:author'],
};
</script>

 

 

9.  v-model 수식어(modifier)핸들링

필요에 따라 v-model 수식어 추가 가능함

 

ex) 첫 글자를 대문자로 표시하는 capitalize 수식어 만들기

<CustomInput v-model.capitalize="username"></CustomInput>

<---컴포넌트에 추가된 수식어는 modelModifiers props를 통해 컴포넌트에 전달됨--!>
<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'],
	setup(props, context) {
		// {capitalize: true} 출력
    console.log(props.modelModifiers);
  },
};
</script>

<--- 이벤트를 내보내기 전에 문자열 첫 글자를 대문자로 만들기 --!>
<template>
  <input type="text" :value="modelValue" @input="emitValue" />
</template>
<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: { default: () => ({}) },
  },
  emits: ['update:modelValue'],
  setup(props, { emit }) {
    const emitValue = (e) => {
      let value = e.target.value;
      if (props.modelModifiers.capitalize) {
        value = value.charAt(0).toUpperCase() + value.slice(1);
      }
      emit('update:modelValue', value);
    };
    return {
      emitValue,
    };
  },
};
</script>

'project > Vue.js' 카테고리의 다른 글

20_slot  (0) 2024.12.26
19_Non-Prop 속성(fallthrough속성)  (0) 2024.12.24
17_Props  (0) 2024.12.23
16_Single-File Component (SFC)  (0) 2024.12.12
15_컴포넌트 기초  (0) 2024.12.12