음악, 삶, 개발
내가 만든 컴포넌트를 다른 컴포넌트 속으로 집어넣기 : <slot> 과 v-slot:이름 본문
Lee : 이 포스팅은 지속적으로 업데이트 되어야합니다. (마지막 업데이트 : 2020.12.7)
< 공식 문서 >
v3.vuejs.org/guide/component-slots.html#slot-content
< slot 의 기초 >
Vue 는 여러 컴포넌트 (.vue 파일) 들을 직접 만들고, 이들을 레고처럼 조립해나가는 방식이다.
이때 2가지 상황이 존재한다.
<template>
<div>
<div></div>
</div>
</template>
위와 같은 상황은 우리가 예상한대로 동작을 한다.
div 는 내가 만든 컴포넌트가 아니라, HTML 에서 제공하는 컴포넌트이다.
하지만 이게 div 가 아닌 내가 만든 컴포넌트라면?
<template>
<my-component-a>
<my-component-b/>
</my-component-a>
</template>
<script>
import MyComponentA from './MyComponentA'
import MyComponentB from './MyComponentB'
export default {
components : { MyComponentA, MyComponentB }
}
</script>
내가 만든 컴포넌트안에 또 다시 내가 만든 컴포넌트를 집어넣었다.
기본적으로 이렇게 하기위해서 필요한것이 <slot> 태그이다.
<slot> 태그는 부모가 자식이 들어오기를 기대하는 위치에, 자리를 만들어놓는것이다.
그러면 자식이 들어왔을때 해당 자리로 들어가게되는것이다.
<!-- MyComponentA.vue -->
<template>
<div id="my-component-a">
<slot></slot> <!-- 자식이 들어올 자리! -->
</div>
</template>
이제 자식 컴포넌트를 간단히 만들어보고..
<!-- MyComponentB.vue -->
<template>
<div id="my-component-b"></div>
</template>
App.vue 에서 my-component-b 를 my-component-a 로 집어넣었다.
<!-- App.vue -->
<template>
<my-component-a>
<my-component-b/>
</my-component-a>
</template>
<script>
import MyComponentA from './MyComponentA'
import MyComponentB from './MyComponentB'
export default {
components : { MyComponentA, MyComponentB }
}
</script>
출력해보면..
우리가 부모 컴포넌트의 slot 태그위치에 자식 컴포넌트가 삽입된것을 알수있다.
아래와 같은 모습도 가능하다.
<my-component-a>
<button>button</button>
</my-component-a>
정리를 하면,
우리가 만든 컴포넌트 (.vue 파일) 가, <slot> 태그를 포함하느냐 안하느냐에 따라
컴포넌트를 template 에서 사용할때 모습이 틀리다.
<!-- 내부적으로 <slot> 태그가 없는 경우 -->
<my-component-a/>
<!-- 내부적으로 <slot> 태그가 있는 경우 -->
<my-component-a></my-component-a>
<slot> 태그가 없는데, 바로 태그를 닫지않더라도
에러가 나는것은 아니지만 가독성 측면에서 이를 지키는것이 좋을것이다.
< 여러개의 slot 가지기 : slot 의 name 속성 + v-slot >
하지만, 대부분의 경우 위의 상황과 달리, slot 이 여러개가 필요할 가능성이 높다.
이럴때는 각 slot 태그에 name 속성에 이름을 붙여 unique id 를 제공해주면 된다.
<!-- MyComponentA.vue -->
<template>
<div id="my-component-a">
<slot name="a"></slot>
<slot name="b"></slot>
<slot name="c"></slot>
<slot name="d"></slot>
</div>
</template>
이렇게 한뒤, 사용할때는 slot 이 1개 일때보다는 조금 복잡하다.
<!-- App.vue -->
<template>
<my-component-a>
<template v-slot:a> <button>a</button> </template>
<template v-slot:b> <span>b</span> </template>
<template v-slot:c> <div>c</div> </template>
<template v-slot:d> <button>d</button> </template>
</my-component-a>
</template>
반드시 삽입하려는 자식 컴포너트를 template 태그로 감싼뒤, v-slot:slot이름 을 해주어야한다.
v-slot 뒤에 있는 slot 이름으로 자식 컴포넌트가 삽입되기때문에,
순서가 아래같이 달라져도,
<template>
<my-component-a>
<template v-slot:d> <button>d</button> </template>
<template v-slot:c> <div>c</div> </template>
<template v-slot:a> <button>a</button> </template>
<template v-slot:b> <span>b</span> </template>
</my-component-a>
</template>
부모 컴포넌트에서 정의한 순서로 랜더링되게된다.
결과적으로..