source

Vue js 2를 사용하여 구성 요소 하위 구성 요소 체인에서 이벤트를 버블링하려면 어떻게 해야 합니까?

factcode 2022. 8. 16. 23:17
반응형

Vue js 2를 사용하여 구성 요소 하위 구성 요소 체인에서 이벤트를 버블링하려면 어떻게 해야 합니까?

vue 어플리케이션을 사용하고 있는 경우:

컴포넌트-자녀로 이루어진 컴포넌트-부모 컴포넌트

inside component-parent 버튼이 있습니다.누군가 버튼을 클릭하면 vue에 의해 처리되어 다른 컴포넌트로 전달되기 위해 이벤트를 내보내고 싶습니다.

지금까지 한 일:

var vm = new Vue({
    el: '#app',
    methods: {
        itemSelectedListener: function(item){
            console.log('itemSelectedListener', item);
        }
    }
});

Vue.component('component-child', {
    template: ' <span  v-on:click="chooseItem(pty )" >Button  </span>',
    methods: {
        chooseItem: function(pty){
            console.log(pty);
            this.$emit('itemSelected', {
                'priority' : pty
            });
        }
    }
});

Vue.component('component-parent', {
    template: '<component-child  v-for="q in items" ></component-child>'
});

HTML:

<component-parent v-on:itemSelected="itemSelectedListener"  ></component-parent>

내 손에 닿다console.log(pty);라인이지만 그런 것 같다this.$emit('itemSelected'통과할 수 없음:

console.log('itemSelectedListener', item); // this is not going to be called...

힌트?

이벤트를 자녀->부모->Vue-instance에서 버블링해야 합니까?(나도 시도해봤지만 성공하지 못했어)

고객님께 문제가 하나 있습니다.component-parent여러 개의 하위 구성 요소를 렌더링하려고 할 때 템플릿이 사용됩니다.Vue는 일반적으로 구성 요소 내부에 단일 루트 div가 필요하므로 div 또는 다른 태그로 래핑해야 합니다.

<div>
    <component-child  v-for="q in items"></component-child>
</div>

두 번째 포인트는 하위 컴포넌트에서 이벤트를 2레벨 아래로 내보내고 루트로 재생하는 것입니다.

Root //but you listen to the event up here 1 level above
 Component 1 //you should listen to the event here
  Component 2 //your try to emit it from here

여기에는 두 가지 옵션이 있습니다.어느쪽인가에서 방출하다component-child에서 그 사건을 듣다component-parent그 이벤트를 위로 전파합니다.https://jsfiddle.net/bjqwh74t/29/ 를 조작합니다.

두 번째 옵션은 이른바 글로벌 등록입니다.bus이 인스턴스는 부모 구성 요소가 아닌 구성 요소 간에 통신하려는 경우에 사용할 수 있는 빈 vue 인스턴스입니다.https://jsfiddle.net/bjqwh74t/30/ 를 조작합니다.

일반적으로 상위 컴포넌트와 하위 컴포넌트 사이에서 이벤트를 직접 사용하여 하위 컴포넌트에서 내보내고 상위 컴포넌트에서 이벤트를 청취합니다.v-on:event-name="handler"그러나 성분 간의 수준이 더 높은 경우에는 두 번째 방법을 사용합니다.

첫 번째 케이스의 Doc 링크:https://vuejs.org/v2/guide/components.html#Using-v-on-with-Custom-Events

두 번째 케이스의 Doc 링크: 。https://vuejs.org/v2/guide/components.html#Non-Parent-Child-Communication

PS: 이벤트 이름에 kebab-case를 사용하는 것을 선호합니다.즉, 다음과 같이 씁니다.-대문자 대신.대문자로 쓰는 것은 사건이 근원적으로 잡히지 않는 이상한 상황을 초래할 수 있습니다.

브라우저의 이벤트 API를 사용할 수 있습니다.Vue에 내장된 것보다 조금 더 많은 스크립트가 필요하지만 이러한 버블링 문제를 해결할 수 있습니다(또한 승인된 답변과 같은 코드 양입니다).

하위 구성 요소:

this.$el.dispatchEvent(new CustomEvent('itemSelected', { detail: { 'priority' : pty }, bubbles: true, composed: true });

컴포넌트의 , 「」의mounted다음 중 하나:

mounted() {
    this.$el.addEventListener('itemSelected', e => console.log('itemSelectedListener', e.detail));
}

조금 늦었지만 방법은 다음과 같습니다.

component-child:

this.$root.$emit('foobar',{...});

컴포넌트 부모:

this.$root.$on('foobar')

'자성분'이라고 쓰면 .$emit$root음음음같 뭇매하다

v-on:click="$root.$emit('hamburger-click')"

다음 : "합니다.mounted라이프 사이클 훅은 다음과 같습니다.

  export default {
    <snip...>
    mounted: function() {
      this.$root.$on('hamburger-click', function() {
        console.log(`Hamburger clicked!`);
      });
    }
  }

아무도 이벤트 버스 컴포넌트를 사용할 것을 제안하지 않았다니 조금 놀랐습니다.고도로 분리된 시스템에서는 공유 이벤트버스가 있으며, 이를 사용하여 여러 개의 분리된 컴포넌트를 pub/sub 스타일로 링크하는 것이 매우 일반적인 패턴입니다.

//eventbus.js
import Vue from 'vue'

export const EventBus = new Vue()

이벤트만 있으면 어디서든 쉽게 게시할 수 있습니다.

// component1.js
import { EventBus } from '@/services/eventbus'
...
EventBus.$emit('do-the-things')

그리고 다른 곳에서 들어보십시오.

// component2.js
import { EventBus } from '@/services/eventbus'
...
EventBus.$on('do-the-things', this.doAllTheThings)

두 컴포넌트는 서로에 대해 아무것도 모르기 때문에 이벤트가 발생한 방법이나 이유는 신경 쓸 필요가 없습니다.

이 접근법에는 잠재적으로 바람직하지 않은 부작용이 있다.이벤트 이름은 앱을 혼동하지 않도록 글로벌하게 고유해야 합니다.또한 보다 정교한 작업을 수행하지 않는 한 모든 이벤트를 단일 개체를 통해 채널링할 수도 있습니다.자신의 앱 소스에서 비용/편익 분석을 수행하여 자신에게 적합한지 확인할 수 있습니다.

버블링을 위한 커스텀 디렉티브를 생성하여 자 컴포넌트에서 사용합니다.

지시문 예시:

// Add this to main.ts when initializing Vue
Vue.directive('bubble', {
  bind(el, { arg }, {context, componentInstance}) {
    if (!componentInstance || !context || !arg) {
      return;
    }

    // bubble the event to the parent
    componentInstance.$on(v, context.$emit.bind(context, arg));
  }
});

하위 구성 요소는 이 명령을 사용하여 상위 구성 요소를 통해 내보낼 수 있습니다(kabob 대소문자 및 이벤트 줄임말로 전환했습니다).

<!-- template for component-parent -->
<component-child v-bubble:item-selected  v-for="q in items"></component-child>

<!-- usage of component-parent -->
<component-parent @:item-selected="itemSelectedListener"></component-parent>

아래 제 풀바인드 지시도 포함해서요.여러 이벤트를 버블링할 수 있습니다.

<!--------------------
 * A few examples 
--------------------->
<!-- bubble single event -->
<child v-bubble:click/>
<child v-bubble:_.click/>
<child v-bubble="'click'"/>
<child v-bubble:any-costume-event-will-work/>

<!-- bubble: click, focus, blur -->
<child v-bubble:_.click.focus.blur/> 
<child v-bubble="'click, focus, blur'"/>

<!-- prefixed bubbling: click, focus, blur as child-click, child-focus, child-blur -->
<child v-bubble:child.click.focus.blur/> 
<child v-bubble:child="'click, focus, blur'"/>
Vue.directive('bubble', {
        bind(el, { value, arg: prefix = '', modifiers }, {context, componentInstance}) {
  const events = value && value.trim() ? value.split(',') : Object.keys(modifiers);
    if (!events.length && prefix) {
      events.push(prefix);
      prefix = '';
    } else if(prefix) {
      prefix = prefix === '_' ? '' : prefix += '-';
    }

    if (!componentInstance || !context || !events.length) {
      return;
    }

    events.forEach((v: string) => {
      v = v.trim();
      const eventName = `${prefix}${v}`;
      const bubble = context.$emit.bind(context, eventName);
      componentInstance.$on(v, bubble);
    });
  }
});

언급URL : https://stackoverflow.com/questions/42029150/how-to-bubble-events-on-a-component-subcomponent-chain-with-vue-js-2

반응형