본문 바로가기
Vue

[Vue] 이벤트를 상속시켜주는 Emit

by 메이플 🍁 2022. 6. 17.

부모 컴포넌트의 이벤트 상속받기

부모 컴포넌트의 속성을 자식 컴포넌트가 상속받을 수 있었던 것처럼 이벤트도 자식 컴포넌트에 상속 시킬 수 있다.

<--! App.vue -->
<template>
  <MyBtn @click="log">Banana</MyBtn>
</template>

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

export default {
  name: 'App',
  components: {
    MyBtn,
  },
  methods: {
    log(event) {
      console.log(event);
      console.log('Click');
    },
  },
};
</script>

 

부모 컴포넌트에서 받은 이벤트는 최상위 요소(루트 요소)에게만 전달된다. 아래 예제에서 최상위 컴포넌트는 btn이라는 클래스를 가진 div 요소이므로 해당 요소에 이벤트 @click="log"가 추가된다.

<!-- MyBtn.vue -->
<template>
  <div class="btn">
    <slot></slot>
  </div>
</template>

<style scoped>
.btn {
  display: inline-block;
  margin: 4px;
  padding: 6px 12px;
  border-radius: 4px;
  background-color: gray;
  color: white;
  cursor: pointer;
}
</style>

 

만약 부모 컴포넌트의 이벤트를 상속받고 싶지 않다면 inheritAttrs에 false값을 주면 된다.

<!-- MyBtn.vue -->
<template>
  <div class="btn">
    <slot></slot>
  </div>
</template>

<script>
export default {
  inheritAttrs: false,
};
</script>

<style scoped>
.btn {
  display: inline-block;
  margin: 4px;
  padding: 6px 12px;
  border-radius: 4px;
  background-color: gray;
  color: white;
  cursor: pointer;
}
</style>

 

만약 최상위 요소가 여러개면 부모 컴포넌트의 이벤트는 상속되지 않는다.

<!-- MyBtn.vue -->
<template>
  <div class="btn">
    <slot></slot>
  </div>
  <p>I love fruits</p>
</template>

<style scoped>
.btn {
  display: inline-block;
  margin: 4px;
  padding: 6px 12px;
  border-radius: 4px;
  background-color: gray;
  color: white;
  cursor: pointer;
}
</style>

 

한개 이상의 최상위 요소가 있을때 부모 컴포넌트의 이벤트를 상속받을 수 있는 방법

1. 부모 컴포넌트에서 상속받고 싶은 이벤트를 emits의 배열에 등록해준다

export default {
  emits: ['click', 'writeClick', 'changeMsg'],
}

2. emits 배열에 등록된 이벤트를 사용하기 위해 emit 메서드를 실행시켜준다

$emit('emits 배열에 등록된 이벤트이름', 인수...)

App.vue 컴포넌트에서 MyBtn이라는 컴포넌트에 @write-click이라는 이벤트를 전달해주고 있다. @write-click 이벤트가 실행되면 log 메서드가 실행되어 콘솔창에 해당하는 이벤트 객체가 출력되고 문자열 'Click'이 출력된다.

<--! App.vue -->
<template>
  <MyBtn @write-click="log">Banana</MyBtn>
</template>

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

export default {
  name: 'App',
  components: {
    MyBtn,
  },
  methods: {
    log(event) {
      console.log(event);
      console.log('Click');
    },
  },
};
</script>

 

부모 컴포넌트에서 상속하고 싶은 이벤트이름을 가져와 emits라는 배열 안에 넣어 만든 후 사용하고 싶은 이벤트를 요소에 넣어준다. 부모컴포넌트에서 전달한 @write-click라는 이벤트를 emits의 배열 안에 넣어준 후 div에 연결해주었다. 이렇게 emits에 상속받은 이벤트를 넣어주면 자식 컴포넌트의 최상위 요소가 아니어도 이벤트를 상속받을 수 있게된다. 아래의 예제에서는 div요소를 click 했을때 부모 컴포넌트에 등록된 writeClick 이벤트가 실행되고 event 객체를 넘겨주게 된다.

<!-- MyBtn.vue -->
<template>
  <!-- click이벤트가 일어났을때 부모 컴포넌트에 등록된 writeClick 이벤트를 실행시켜준다 -->
  <!-- writeClick 이벤트는 부모 컴포넌트에서 log 메서드를 실행시켜준다 -->
  <!-- 이 메서드는 파라미터로 event를 가지는데 emit 메서드의 두번째 인자 이벤트객체를 전달받는다 -->
  <div class="btn" @click="$emit('writeClick', $event)">
    <slot></slot>
  </div>
</template>

<script>
export default {
  // 부모 컴포넌트에서 상속하고 싶은 모든 이벤트를 등록해준다
  emits: ['writeClick'],
}
</script>

<style scoped>
.btn {
  display: inline-block;
  margin: 4px;
  padding: 6px 12px;
  border-radius: 4px;
  background-color: gray;
  color: white;
  cursor: pointer;
}
</style>

 

부모 컴포넌트에서 자식 컴포넌트에 있는 input의 value값 가져오기

자식 컴포넌트에 있는 watch 옵션은 어떤 데이터를 계속 감시하는 옵션이다. 감시하고 싶은 데이터를 메소드로 만들어주고 그 안에 해당 데이터가 변화될때마다 실행하고 싶은 로직을 넣어준다.

 

아래 예제에서는 msg 데이터가 변화될때마다 msg() 메서드가 실행된다. 즉 사용자가 어떤 값을 input에 넣으면 그 값이 msg의 값으로 업데이트되고 watch 옵션 안에 등록한 msg() 메서드가 실행된다. msg() 메서드가 실행이 되면 부모 컴포넌트에서 상속받은 이벤트 changeMsg가 불려져 logMsg() 메서드가 실행되어지며 인수로 this.msg 즉 msg가 전달되어진다.

<--! App.vue -->
<template>
  <MyBtn @change-msg="logMsg">Banana</MyBtn>
</template>

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

export default {
  name: 'App',
  components: {
    MyBtn,
  },
  methods: {
    logMsg(msg) {
      console.log(msg);
    },
  },
};
</script>
<!-- MyBtn.vue -->
<template>
  <div class="btn">
    <slot></slot>
  </div>
  <div><input type="text" v-model="msg" /></div>
  <p>{{ msg }}</p>
</template>

<script>
export default {
  // 부모 컴포넌트에서 상속하고 싶은 모든 이벤트를 등록해준다
  emits: ['changeMsg'],
  data() {
    return {
      msg: '',
    };
  },
  watch: {
    msg() {
      this.$emit('changeMsg', this.msg);
    },
  },
}
</script>

<style scoped>
.btn {
  display: inline-block;
  margin: 4px;
  padding: 6px 12px;
  border-radius: 4px;
  background-color: gray;
  color: white;
  cursor: pointer;
}
</style>

댓글