VueJS 2.0 emit event from grand child to his grand parent component


Parece que el SDV.js 2.0 no emite eventos de un nieto a su componente abuelo padre.

Vue.component('parent', {
  template: '<div>I am the parent - {{ action }} <child @eventtriggered="performAction"></child></div>',
  data(){
    return {
      action: 'No action'
    }
  },
  methods: {
    performAction() { this.action = 'actionDone' }
  }
})

Vue.component('child', {
  template: '<div>I am the child <grand-child></grand-child></div>'
})

Vue.component('grand-child', {
  template: '<div>I am the grand-child <button @click="doEvent">Do Event</button></div>',
  methods: {
    doEvent() { this.$emit('eventtriggered') }
  }
})

new Vue({
  el: '#app'
})

Este JsFiddle resuelve el problema https://jsfiddle.net/y5dvkqbd/4 / , pero emitiendo dos eventos:

  • Uno de nieto a componente medio
  • Luego emitiendo de nuevo desde el componente medio al gran padre

Agregar este evento intermedio parece repetitivo y innecesario. ¿Hay alguna manera de emitir directamente al abuelo que no estoy consciente de?

Author: Bassem El Hachem, 2017-03-06

3 answers

La comunidad Vue generalmente favorece el uso de Vuex para resolver este tipo de problema. Se realizan cambios en el estado Vuex y la representación DOM simplemente fluye de eso, eliminando la necesidad de eventos en muchos casos.

Salvo eso, volver a emitir probablemente sería la siguiente mejor opción, y por último podría optar por usar un bus de eventos como se detalla en la otra respuesta altamente votada a esta pregunta.

La respuesta a continuación es mi respuesta original a esta pregunta y no es un enfoque I tomaría ahora, tener más experiencia con SDV.


Este es un caso en el que podría estar en desacuerdo con la elección de diseño de Vue y recurrir a DOM.

En grand-child,

methods: {
    doEvent() { 
        try {
            this.$el.dispatchEvent(new Event("eventtriggered"));
        } catch (e) {
            // handle IE not supporting Event constructor
            var evt = document.createEvent("Event");
            evt.initEvent("eventtriggered", true, false);
            this.$el.dispatchEvent(evt);
        }
    }
}

Y en parent,

mounted(){
    this.$el.addEventListener("eventtriggered", () => this.performAction())
}

De lo contrario, sí, tienes que volver a emitir, o usar un bus.

Nota: Agregué código en el método doEvent para manejar IE; ese código podría extraerse de una manera reutilizable.

 19
Author: Bert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-08 15:32:34

Sí, los eventos correctos solo van de hijo a padre. No van más allá, por ejemplo, de niño a abuelo.

La documentación del SDV (brevemente) aborda esta situación en la sección Comunicación No Padre-Hijo.

La idea general es que en el componente abuelo se crea un componente Vue vacío que se pasa de abuelo a los hijos y nietos a través de accesorios. El abuelo escucha los eventos y los nietos emiten eventos en ese "bus de eventos".

Algunas aplicaciones utilizan un bus de eventos global en lugar de un bus de eventos por componente. El uso de un bus de eventos global significa que necesitará tener nombres de eventos o espacios de nombres únicos para que los eventos no entren en conflicto entre diferentes componentes.

Aquí hay un ejemplo de cómo implementar un simple bus de eventos global.

 15
Author: Sly_cardinal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-06 00:10:42

Otra solución será:

Usa vm.$root.$emiten nieto, luego usa vm.$root.$on en el antepasado (o en cualquier lugar que desee).

Vue.component('parent', {
  template: '<div>I am the parent - {{ action }} <child @eventtriggered="performAction"></child></div>',
  data(){
    return {
      action: 'No action'
    }
  },
  created: function () {
  	this.$root.$on('eventtriggered1', () => {
    	this.performAction()
    })
  },
  methods: {
    performAction() { this.action = 'actionDone' }
  }
})

Vue.component('child', {
  template: '<div>I am the child <grand-child @eventtriggered="doEvent"></grand-child></div>',
  methods: {
    doEvent() { 
    	//this.$emit('eventtriggered') 
    }
  }
})

Vue.component('grand-child', {
  template: '<div>I am the grand-child <button @click="doEvent">Do Event</button></div>',
  methods: {
    doEvent() { this.$root.$emit('eventtriggered1') }
  }
})

new Vue({
  el: '#app'
})
<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <parent></parent>
</div>
 5
Author: Sphinx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-02 20:24:26