한 번에 끝내는 프론트엔드 개발 초격차 패키지 Online를 들으며 정리한 내용입니다.
App.vue
<template>
<MyBtn @click="log">
Banana
</MyBtn>
</template>
<script>
import MyBtn from '~/components/MyBtn'
export default {
components: {
MyBtn
},
methods: {
log() {
console.log('Click!!')
}
}
}
</script>
MyBtn.vue
<template>
<div class="btn">
<slot></slot>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.btn {
display: inline-block;
margin: 4px;
padding: 6px 12px;
border-radius: 4px;
background-color: gray;
color: white;
cursor: pointer;
}
</style>
MyBtn라는 컴포넌트를 클릭하면 log라는 함수가 실행될 수 있는 구조입니다. 하지만 이벤트는 화면에 있는 특정한 엘리먼트에 연결되어 있어야지만 동작을 합니다.
현재 자식 컴포넌트의 최상위 요소가 1개이며 따로 inheritAttrs:false
가 작성되어 있지 않기에 속성 상속을 통해 이벤트는 잘 연결이 되고 실행될 수 있게 됩니다.
그렇다면 inheritAttrs:false
옵션을 사용해야하거나, 자식 컴포넌트의 최상위 요소가 2개이상인 경우에는 어떻게 해야할까요?
이러한 경우 해당하는 요소에 이벤트를 직접적으로 연결해줄 수 있습니다.
자식 컴포넌트의 최상위 요소가 2개인 경우를 가정해보도록 하겠습니다.
<template>
<div class="btn">
<slot></slot>
</div>
<h1></h1>
</template>
아래와 같이 자식 컴포넌트의 script부분에 emits이라는 옵션을 추가해 사용할 이벤트를 정의해줍니다.
<script>
export default {
emits: [
'click'
]
}
</script>
최상위 컴포넌트 중 h1에 적용을 해보도록 하겠습니다.
아래와 같이 @click이라는 이벤트를 emits이라는 옵션을 통해 부모요소에 정의된 내용으로 가지고 와 명시를 한 후 이 명시된 내용을 $emit이라는 하나의 메소드의 첫번째 매개변수로 정의를 해줍니다.
MyBtn.vue
<template>
<div class="btn">
<slot></slot>
<h1 @click="$emit('click')">
ABC
</h1>
</template>
이렇게 특정한 이벤트를 상속받아 emits
라는 옵션에 연결을 해, $emit
이라는 메소드를 통해 실행할 수 있습니다.
이 클릭이라는 이벤트는 MyBtn이라는 컴포넌트의 emits이라는 부분으로 넘어가 내부에서 사용되기 때문에 굳이 click이라는 이름을 부여하지 않아도 괜찮습니다. 컴포넌트에 연결하는 이벤트는 실제로 쓸 수 있는 그 이벤트의 이름이 꼭 아니어도 상관 없습니다.
대신 정확하게 emits라는 옵션으로 받아서 그것이 어디에서 어떻게 사용이 되는지를 명시해줘야합니다.
App.vue
<template>
<MyBtn @heropy="log"> //heropy로 수정
Banana
</MyBtn>
</template>
MyBtn.vue
<template>
<div class="btn">
<slot></slot>
</div>
<h1 @click="$emit('heropy')"></h1> //heropy로 수정
</template>
<script>
export default {
emits: [
'heropy' //heropy로 수정
]
}
</script>
이번에는 이벤트가 실제로 동작했을 때 이벤트 객체를 활용할 수 있는 부분에 대해서 배워보도록 하겠습니다.
App.vue
//App.vue
methods: {
log(event) {
console.log('Click!!'),
console.log(event)
}
MyBtn.vue
<h1 @click="$emit('click', $event )">//두번째 매개변수에 그 이벤트가 실행될 때의 데이터를 넘겨줄 수 있습니다.(이벤트라는 객체전달)
h1태그를 두번 클릭하면 'click!' 다음으로 두번째 매개변수로 들어간 mouseeven라는 객체가 출력되는 것을 확인할 수 있습니다.
input요소를 만들어 v-model이라는 양방향데이터바인딩으로 msg라는 데이터를 한번 연결해보도록 하겠습니다.
<template>
<div class="btn">
<slot></slot>
</div>
<h1 @click="$emit('click', $event )">
ABC
</h1>
<input
type="text"
v-model="msg" />
</template>
<script>
export default {
emits: [
'click'
],
data() {
return {
msg: '' //data라는 옵션을 만들어 msg라는 데이터를 빈 문자열로 정의
}
}
}
</script>
화면의 input박스에 데이터를 입력할 때마다 실시간으로 msg라는 데이터를 갱신하게 되며 양방향데이터바인딩이기 때문에 변경된 msg데이터가 input요소에도 영향을 주고, input요소의 수정된 내용이 다시 msg에 영향을 줄 수 있는 구조가 만들어졌습니다.
sciprt에 watch라는 옵션을 추가해 msg라는 데이터가 변경될 때마다 app.vue에서 그 내용을 확인할 수 있도록 코드를 작성해보도록 하겠습니다.
MyBtn.vue
export default {
emits: [
'click',
'changeMsg' // 2) emits옵션에 명시
],
watch: {
msg(){
this.$emit('changeMsg', this.msg) //1)msg를 감시하며 msg의 내용이 변경될 때마다 카멜케이스로 작성된 changeMsg라는 이벤트를 실행합니다.
}
}
App.vue
<template>
<MyBtn @click="log" @change-msg="logMsg"> 3)✔️ html의 속성을 작성할때는 카멜케이스를 사용하지 않기 때문에 대쉬캐이스로 수정해줘야합니다.
Banana
</MyBtn>
</template>
<script>
import MyBtn from '~/components/MyBtn'
export default {
components: {
MyBtn
},
methods: {
log(event) {
console.log('Click!!'),
console.log(event)
},
logMsg(msg){
console.log(msg) 4) logMsg를 명시
}
}
}
</script>