음악, 삶, 개발

내가 만든 컴포넌트를 다른 컴포넌트 속으로 집어넣기 : <slot> 과 v-slot:이름 본문

개발 Web/Vue.js 공부방

내가 만든 컴포넌트를 다른 컴포넌트 속으로 집어넣기 : <slot> 과 v-slot:이름

Lee_____ 2020. 12. 7. 03:37
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>

부모 컴포넌트에서 정의한 순서로 랜더링되게된다.

결과적으로..