vue2 슬롯 에서 상위로 이벤트 전파

그니·2023년 10월 12일
0
post-thumbnail

계기

버튼과 셀렉트 리스트가 있는 모달을 컴포넌트로 만드는 과정에서 찾아봤습니다. 버튼을 누르면 모달이 열리는 상황에서 모달의 열림/닫힘 여부를 컴포넌트에서 관리하고 모달의 내용은 slot으로 받아 조금 더 유연하게 만드는게 목적 이였으나, 슬롯 사용자는 제공자의 컨텍스트에 접근할 수 없다보니 어떻게 하면 모달을 닫을 수 있을까 하다 찾아봤습니다.

1. 범위가 있는 슬롯(Scoped Slots)

<div class="carousel">
  <div class="slides" ref="slides">
    // (1) scope로 이벤트 전달
    <slot :next="next" :close="close"></slot>
  </div> 
  <footer>
    <!-- Other carousel controls like arrows, indicators etc go here -->
  </footer>
</div>

// (2) 전달받은 이벤트 직접 호출
<my-carousel v-slot="scope">
  <div class="slide">
    <button @click="scope.next">Next</button>
  </div>

  <div class="slide">
    <button @click="scope.close">Close</button>
  </div>
</my-carousel>

2. $parent 프로퍼티 사용

<my-carousel v-slot="scope">
  <div class="slide">
    <button @click="$parent.$emit('next')">Next</button>
  </div>

  <div class="slide">
    <button @click="$parent.$emit('close')">Close</button>
  </div>
</my-carousel>
  1. slot은 내용을 대체한다.
  2. 사용하는 컨텍스트에서 slot을 대체하기에, 제공하는 컨텍스트의 메서드에 접근할 수는 없지만, 렌더링은 제공하는 컨텍스트에 렌더링 되기에 '$parent' 로 접근할 수 있다.

3. $parent + 이벤트 전파용 Wrapper

export default {
    name: 'EventListener'
    render() {
        return this.$slots.default;
    }
}

<div class="carousel">
  <event-listener @next="handleNext" @close="handleClose">
     <div class="slides" ref="slides">
       <slot></slot>
     </div> 
  </event-listener>
  <footer>
   <!-- other carousel controls like arrows, indicators etc go here -->
  </footer>
</div>

<my-carousel>
  <div class="slide">
    <button @click="$parent.$emit('next')">Next</button>
  </div>

  </div class="slide">
    <button @click="$parent.$emit('close')">Close</button>
  </div>
</my-carousel>
  • $parent 프로퍼티 접근으로 한 'next', 'close' 이벤트 전파는 'event-listener' 컴포넌트가 수신한다는 것을 더 명확하게 표현하였으며,
  • 추후 동일한 패턴이 존재할 시 재사용할 수 있다.

참조

  • [https://stackoverflow.com/questions/50942544/emit-event-from-content-in-slot-to-parent]

0개의 댓글