Tempo Di Valse

[Vue.js] 동적 컴포넌트에 이벤트 전달하기 본문

개발/Web

[Vue.js] 동적 컴포넌트에 이벤트 전달하기

TempoDiValse 2022. 5. 4. 13:39

먼저 Vue.js 의 동적 컴포넌트란 무엇인가. 해당 내용은 Vue.js 문서에 잘 나와있다.

 

동적 & 비동기 컴포넌트 — Vue.js

Vue.js - 프로그레시브 자바스크립트 프레임워크

kr.vuejs.org

 

간단하게 실무쪽으로 사용하는 방법에 대해서 예시로 설명하자면, 

 

- 여러 컴포넌트가 있다. 이 때 컴포넌트 들은 거의 같은 구조를 가지고 있다. (다른 구조를 가지고 있어도 상관없긴 함)

- 컴포넌트는 한 곳에서 번갈하가면서 뿌려줘야 한다.

- 컴포넌트는 비슷한 상호작용을 할 수 있어야 한다.

 

할 때에 코드로 작성하게되면, 일반적으로 기초만 배웠을 때에는 다음처럼 코딩을 작성할 것이다.

<template>
    <div>
    	<content-two v-if="currentContent === 1" />
        <content-three v-else-if="currentContent === 2" />
        <content-four v-else-if="currentContent === 3" />
        <content-one v-else />
    </div>
</template>

<script>
import ...

export default {
    name: "Body",
    component: { ... },
    data(){
    	return {
            currentContent: 0
        }
    }
}
</script>

그리고 각 콘텐트 태그들은 다음의 내용을 가지고 있다고 한다.

<button>Content {{ n }}</button>

겉보기에는 괜찮을 수 있지만, 이 컴포넌트에 성향이 다른 컴포넌트가 추가된다면 유지보수와 코드 파일 하나의 목적이 중구난방으로 될 수 있다. 그렇기 때문에 성격상 같은 아이들을 한데 묶을 필요가 있다.

 

그래서 저 content-one...four 까지 한 곳으로 묶기 위해서 <component> 태그를 사용하도록 한다. 각 콘텐트 태그들의 내용도 단순하기 때문에 지역 컴포넌트 등록으로 파일 생성 과정을 줄이도록 한다.

<template>
    <div>
    	<component :is="currentContent" />
    </div>
</template>

<script>
const ContentOne = {
    template: '<button>Content One</button>'
}

/* ...같은 내용 반복 */

export default {
    name: "Body",
    component: { ContentOne, ... },
    data(){
    	return {
            currentContent: 'ContentOne'
        }
    }
}
</script>

이런식으로 바꾸게 되면 같은 성격을 가지고 있는 콘텐트 태그들은 <component> 태그를 통해서 묶여져 보여질 수 있고, 탭 이라던가 버튼 선택 같은 다른 트리거를 통해서 <component> 에 보여지는 내용들을 달리 할 수가 있다.

 

그러나 한가지 궁금한 점이 생겨버렸었다. 그것은 "지역 등록한 컴포넌트에서 동적 컴포넌트에 이벤트를 어떻게 전달하는 가." 였다. 지역 등록 컴포넌트는 템플릿만 있는데다가 데이터를 처리할 중심역할을 하는 변수들은 default 객체 안에 있어서 접근할 수가 없을 것 같다 생각 할 수도 있다.

 

하지만, 다음의 방법으로 해결을 할 수 있다. button 이 콘텐트 태그의 내부 내용으로 있기 때문에 click 이벤트 를 통해서 동적 컴포넌트로 전달하는 방법을 예시로 삼도록 하겠다.

 

먼저, <component> 태그에 click 이벤트를 심어보자.

<template>
    <div>
    	<component :is="currentContent" @click=""/>
    </div>
</template>

단순하게 click 에 대한 이벤트는 심어놓지 않았다. 여기에는 아무 로직이나 사용하면 되는 것이기 때문에 그냥 자리만 만들어 놓았다. 기초적인 생각이라면 <component> 에 @click 만 달면 작동하지 않은가 할 테지만, 실질적으로 <component> 태그는 아무것도 없는 빈 껍데기라고 생각하면 된다. 그렇기 때문에 <component> 태그 안에는 click 이벤트 자체가 커스텀 이벤트가 되어 콘텐트 파일에서 <component> 에 이벤트가 일어날 수 있도록 전달해 주어야 한다. 그래서 콘텐트 파일 template 부분을 조금 수정해준다.

const ContentOne = {
    template: '<button @click="$emit('click')">Content One</button>'
}

실질적으로 이벤트는 <button> 태그로부터 이뤄지기 때문에 <button> 에 click 이벤트를 달아주었고, Vue 의 $emit 메소드를 통해서 이벤트를 전달해 주었다. 그래서 <component> 태그에서는 click 이라는 이벤트가 호출되었다는 것을 감지하고 click 이벤트에 걸어놓은 메소드 트리거를 실행시키게 되는 것이다.

 

참 쉬웠죠.

반응형
Comments