programing

Vue.js - 부모 <-> 슬롯 통신

bestcode 2022. 8. 31. 22:44
반응형

Vue.js - 부모 <-> 슬롯 통신

향후 프로젝트에서 사용할 라이브러리를 작성하기 위해 Vue 컴포넌트의 작은 컬렉션을 작성하려고 합니다만, 이 토픽은 매우 혼란스럽습니다.전혀 다른 접근방식이 필요할지도 모르지만...

정책 패턴에서 영감을 얻고 있습니다(이렇게 부릅니다).템플릿 컴포넌트를 만듭니다.템플릿 컴포넌트의 동작은 중첩된 컴포넌트에 따라 달라집니다.예를 들어 bkg 이미지를 변경하는 메서드를 소유하는 Preview 컴포넌트를 만들고 이 메서드를 호출할 수 있는 오버레이를 이 컴포넌트에 중첩하려고 합니다.이 오버레이는 슬롯을 통해 네스트되어 있으면 좋겠다고 생각했던 모든 것이 될 수 있기 때문에:

<template>
  <div class="preview" :class="{active: active}">
    <div class="content">
      <slot name="content"></slot>
    </div>
    <div class="overlay"><slot></slot></div>
    </div>
</template>

(img 목록을 통해 콘텐츠를 v-for로 만듭니다.)

그리고 js:

props: {
    content: {default: function () { return [] }}
  },
  data: function () {
    return {
      preview: null
    }
  },
  methods: {
    setPreview: function (e) {
      this.preview = e
    }
  }
}

다음으로 변경 온마우스 오버를 트리거하는 하위 구성 요소가 있습니다.

<template>
  <div @mouseover="set">
    <slot></slot> <!-- some random content -->
  </div>
</template>

<script>
export default {
  props: ['target']
  methods: {
    set: function () {
      // figure a way to call "parent" setPreview
    }
  }
}
</script>

그리고 이 컴포넌트를 다음과 같이 사용합니다.

<preview>
  <template slot="content">... a bounch of v-if bound images</template>
  <template>
    <change-preview-onover target="first-img">...</change-preview-onover>
    <change-preview-onclick target="second-img">...</change-preview-onclick> <!-- different policy -->
  </template>
</preview>

스코프 슬롯과 제공/인젝트라는 두 가지 접근 방식을 시도했습니다.스코프 슬롯에서는 다음과 같은 결과가 나옵니다.

//preview
<template>
  <div class="preview" :class="{active: active}">
    <div class="content">
      <slot name="content"></slot>
    </div>
    <div class="overlay" :callback="{setPreview}"><slot></slot></div>
    </div>
</template>
//js...

//overlay element
<template>
  <div @mouseover="set">
    <slot></slot> <!-- some random content -->
  </div>
</template>
<script>
export default {
  props: ['target', 'callback']
  methods: {
    set: function () {
      this.callback.setPreview(this.target)
    }
  }
}
</script>

//usage
<preview>
  <template slot="content">... a bounch of v-if bound images</template>
  <template slot-scope={callback}>
    <change-preview-onover :callback="callback" target="first-img">...</change-preview-onover>
    <change-preview-onclick :callback="callback" target="second-img">...</change-preview-onclick>
  </template>
</preview>

이 방법은 캡슐화가 깨지고(사용자는 콜백의 존재를 알고 모든 변경 미리보기 컴포넌트를 통해 콜백을 전달해야 함) 많은 용장 코드를 얻을 수 있기 때문에 좋아하지 않습니다.슬롯 스코프를 오버레이 컴포넌트 안쪽으로 옮기려고 했지만 잘 되지 않았습니다.제공/주입에 대해 읽은 적이 있는데, 기본적으로 다음과 같습니다.

//preview.js
provide: function () {
  return {
    setPreview: this.setPreview
  }
}

//overlay.js
inject: ['setPreview'],
props: ['target'],
methods: {
  set: function () {
    this.setPreview(this.target)
  }
}

이 방법은 매우 멋있어 보이지만 제공/주입이 그렇게 되어 있는지, 아니면 어디에서나 사용해도 괜찮은지(주로 퍼포먼스를 중시하고 있습니다), 부모<->슬롯 통신을 작성하기 위해서입니다.물론 슬롯은 의미론적으로 부모에 연결되어 있습니다.

편집 1

Vue.js에는 부모 자녀의 통신을 처리하는 표준 방법이 있습니다.

부모/자녀

단, Vue가 컴포넌트의 범위를 처리하는 방법 때문에 슬롯에서는 동작하지 않습니다.이 예에서 미리보기는 구성요소 템플릿 내에 직접 중첩되지 않으므로 중첩의 상위 항목이 아닙니다.대신 이렇게 쓰면:

<template>
  <div class="preview" :class="{active: active}">
    <content>...<content> <!-- changes here -->
    <overlay>...</overlay> <!-- and here -->
  </div>
</template>

Overlay 및 Content는 이벤트를 내보내는 Preview와 자유롭게 통신할 수 있습니다.그러나 앞서 제안했던 첫 번째 예시와 같이 throught 슬롯은 콘텐츠와 오버레이(그리고 미리보기)는 모두 일반적인 앱 콘텐츠의 자식이기 때문에 미리보기가 아니라 앱(또는 미리보기 컴포넌트를 포함하는 것)으로 전송되므로 슬롯에서 부모로 또는 그 반대로 통신하는 새로운 방법이 필요합니다.

이 주제에 대한 주요 스레드: https://github.com/vuejs/vue/issues/4332 여기에서는 scope slot (ok, 하지만 끔찍한) 또는 $parent를 사용하고 있습니다.이 슬롯은 항상 참인 것은 아니기 때문에 사용할 수 없습니다.아마도 전환이나 다른 것을 추가하여 다음과 같은 것을 얻을 수 있습니다.

//Modal
<div>
  <tr-fade> <!-- tr-fade is a registered comopnent and so it's the $parent of slot -->
    <slot></slot>
  </tr-fade>
</div>

질문입니다.제공/주입이 이 케이스에 대한 적절한 대처방법입니까?slot-scope는 imho가 캡슐화를 해제하고 장황하게 설명하더라도 더 적합할까요?또는 슬롯이 제공하는 커스터마이즈 수준을 포기하지 않고 이 '정책 패턴'을 실현하는 다른 방법이 있습니까?

슬롯 내에 자녀의 콘텍스트를 삽입하고 다음 콘텍스트에서 이벤트를 내보낼 수 있습니다.

// the child
<template>
  <div>
    <slot :context="thisContext"/>
  </div>
</template>

<script>
export default
{
  computed:
  {
    thisContext()
    {
      return this;
    }
  }
}
</script>

// the parent
<template>
  <child @custom_event="handleCustom">
    <template slot-scope="ctx">
      <button @click="sendClick(ctx)">Click me</button>
    </template>
  </child>
</template>

<script>
export default
{
  methods:
  {
    sendClick(ctx)
    {
      ctx.$emit('custom_event', {custom_data: 3});
    },
    handleCustom(payload)
    {
      console.log("Custom payload:", payload);
    }
  }
}
</script>

언급URL : https://stackoverflow.com/questions/51427841/vue-js-parent-slot-communication

반응형