2016-06-27 21 views
14

Sto tentando di creare un bus eventi globale in modo che due componenti di pari livello possano comunicare tra loro. Ho cercato in giro; tuttavia, non riesco a trovare alcun esempio su come implementarlo. Questo è quello che ho finora:Bus eventi globale Vue.js

var bus = new Vue(); 

Vue.component('Increment', { 
    template: "#inc", 
    data: function() { 
    return ({count: 0}) 
    }, 
    methods: { 
    increment: function(){ 
     var increment = this.count++ 
     bus.$emit('inc', increment) 
    } 
} 
}) 

Vue.component('Display', { 
    template: "#display", 
    data: function(){ 
    return({count: 0}) 
    }, 
created: function(){ 
    bus.$on('inc', function(num){ 
    alert(num) 
    this.count = num; 
    }); 
} 
}) 


vm = new Vue({ 
el: "#example", 
}) 

ho creato i miei modelli in questo modo: http://codepen.io/p-adams/pen/PzpZBg

mi piacerebbe la componente Increment di comunicare il conteggio alla componente Display. Non sono sicuro di cosa sto sbagliando in bus.$on().

risposta

26

Il problema è che all'interno della funzione bus.$on, this si riferisce al bus. Hai solo bisogno di legare l'istanza Vue corrente a quella funzione utilizzando .bind():

bus.$on('inc', function(num){ 
alert(num) 
this.count = num; 
}.bind(this)); 

Si dovrebbe anche controllare https://github.com/vuejs/vuex se si desidera gestire gli stati applicativi globali.

EDIT: Dal momento che questa pagina sembra avere un sacco di clic che voglio modificare e aggiungere un altro metodo, per ChristopheMarois nei commenti:

bus.$on('inc', (num) => { 
alert(num); 
this.count = num; 
}); 

o rimuovere l'avviso:

bus.$on('inc', (num) => this.count = num); 
+0

Hmm. Ancora non funziona. Non sono sicuro di cosa stia succedendo, visto che non ho mai provato a creare un bus eventi. Ho implementato questo stesso programma in vuex. Proprio questo nella recente guida di vuejs 2, Evan menziona la possibilità di utilizzare un bus eventi per problemi semplici –

+1

che funziona qui: http://codepen.io/anon/pen/KMWzLQ – Jeff

+1

Un bug potrebbe essere che tu sei post- conteggio incrementale con 'var increment = this.count ++;'. Cambialo in 'var increment = ++ this.count;'. In questo modo "count" viene incrementato prima di essere assegnato a "incrementare" – asemahle

3

Mentre si scrive JavaScript ES5, è necessario essere consapevoli del fatto che ciò a cui si fa riferimento utilizzando la parola chiave this potrebbe cambiare, in base all'ambito, da cui viene chiamato.

Una metafora utile per farti un'idea del concetto this consiste nel pensare alle parentesi graffe in ES5 come recinzioni, che contengono/associano il proprio this.

Quando si utilizza this nella funzione di callback del vostro bus evento, this non si riferisce al componente Vue, ma l'oggetto bus, che non ha di conteggio dei dati, quindi i dati si prevede di aggiornare doesn' t.

Se avete/voglia di scrivere ES5 sintassi una soluzione comune (oltre vincolante this come suggerito dalla risposta accettata) è di assegnare la parola chiave this a una variabile in questo modo:

created: function(){ 
    var self = this; 
    bus.$on('inc', function(num){ 
    alert(num) 
    self.count = num; 
    }); 
} 

Se è possibile scrivere ES6, fallo quando possibile. Puoi sempre compilare/traspondere fino a ES5 con Babel. La risposta accettata mostra come utilizzare le funzioni freccia.

Le funzioni di freccia funzionano in questo caso perché non rilevano il proprio this.

di restare con la metafora recinzione: immaginare l'ES6 freccia colpendo un buco in funzione di recinzione, in modo che il esterna this può passare attraverso e si può chiamare this come previsto.

Per ulteriori informazioni sulle funzioni di direzione ES6 visitare: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

+0

questa è l'unica risposta che ha funzionato, pensare a causa della modalità rigorosa ES6 var self = this; è essenziale, altrimenti viene generato un errore – Pixelomo

3

Questo si risponde molto tempo indietro, ecco la mia soluzione con in vue.JS-2

main.js

import Vue from 'vue' 
import App from './App' 

export const eventBus = new Vue({ 
    methods:{ 
    counter(num) { 
     this.$emit('addNum', num); 
    } 
    } 
}); 

new Vue({ 
    el: '#app', 
    template: '<App/>', 
    components: { App } 
}); 

comp1.vue

//Calling my named export 
import { eventBus } from '../../main' 
<template> 
    <div> 
    <h1>{{ count }}</h1> 
    <button @click="counterFn">Counter</button> 
    </div> 
</template> 

<script> 
    import { eventBus } from '../../main' 

    export default { 
    name: 'comp-one', 
    data() { 
     return { 
     count: 0 
     } 
    }, 
    methods: { 
     counterFn() { 
     eventBus.counter(this.count); 
     } 
    }, 
    created() { 
     eventBus.$on('addNum',() => { 
     this.count++; 
     }) 
    } 
    } 
</script> 
+1

è meglio non avere metodi in 'EventBus' perché è globale e interromperà l'incapsulamento in questo caso. Basta usare 'emit' e' on' con l'istanza vue 'EventBus' vuota. È tutto. –

+1

@OlegAbrazhaev Sono d'accordo con te, e in questi giorni sto facendo esattamente quello che hai detto. – Syed

0

come su questo? Si supponga Vue.js 2.

creare un componente Event-Bus riutilizzabile e collegarlo al Vue tramite modello plugin:

// ./components/EventBus.vue 
import Vue from 'vue' 
export const EventBus = new Vue() 

// ./plugins/EventBus.js 
export default { 
    install(Vue) { 
    const { EventBus } = require('../components/EventBus') 
    Vue.prototype.$bus = EventBus 
    } 
} 

// ./main.js 
import EventBus from './plugins/EventBus' 
Vue.use(EventBus) 

Poi, si può fare ovunque nel codice: this.$bus.$emit('some-event', payload)

Come una nota a margine, prova a utilizzare il pattern Event-Bus come ultima risorsa.