Il semble que Vue.js 2.0 n'émet pas d'événements d'un grand enfant à son composant grand parent.
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'
})
Ce JsFiddle résout le problème https://jsfiddle.net/y5dvkqbd/4/ , mais en émettant deux événements:
L'ajout de cet événement intermédiaire semble répétitif et inutile. Existe-t-il un moyen d'émettre directement au grand parent que je ne sache pas?
Oui, vous avez raison, les événements ne vont que d’enfant à parent. Ils ne vont pas plus loin, par exemple de l'enfant au grand-parent.
La documentation de Vue traite (brièvement) de cette situation dans la section Communication non parent-enfant .
L'idée générale est que, dans le composant grands-parents, vous créez un composant Vue
vide qui est transmis des grands-parents aux enfants et petits-enfants via des accessoires. Le grand-parent écoute ensuite les événements et les petits-enfants émettent des événements sur ce "bus d'événements".
Certaines applications utilisent un bus d'événements global au lieu d'un bus d'événements par composant. L'utilisation d'un bus d'événements global signifie que vous devez disposer de noms d'événements uniques ou d'espaces de noms uniques afin que les événements ne se heurtent pas entre différents composants.
Voici un exemple de comment implémenter un simple bus d’événements global .
Une autre solution sera:
Utilise vm.$root.$emit
dans grand-child , puis utilise vm.$root.$on
chez l’ancêtre (ou n’importe où vous voudriez).
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>
NOUVELLE RÉPONSE (mise à jour de novembre 2018)
J'ai découvert que nous pouvions y arriver en exploitant la propriété $parent
dans le composant grand enfant:
this.$parent.$emit("submit", {somekey: somevalue})
Beaucoup plus propre et plus simple.
C'est le seul cas où j'utilise event bus !! Pour transmettre des données d'un enfant imbriqué profond à une communication non directement parent.
First: Créez un fichier js (je l’appelle eventbus.js) avec ce contenu:
import Vue from 'vue'
Vue.prototype.$event = new Vue()
Second: Dans votre composant enfant, émettez un événement:
this.$event.$emit('event_name', 'data to pass')
Third: Dans le parent, écoutez cet événement:
this.$event.$on('event_name', (data) => {
console.log(data)
})
Note: Si vous ne voulez plus de cet événement, veuillez le désinscrire:
this.$event.$off('event_name')
INFO: Pas besoin de lire l'opinion personnelle ci-dessous
Je n'aime pas utiliser Vuex pour la communication grand-enfant à grand-parent (ou niveau de communication similaire).
Dans vue.js, vous pouvez utiliser fournir/inject pour transmettre des données de grand-parent à petit-enfant. Mais il n'y a pas quelque chose de similaire pour la chose opposée. (petit-enfant à grand-parent) J'utilise donc Event Bus chaque fois que je dois faire ce genre de communication.