如何在vue.js 1.0.x中使用全局事件总线?

时间:2016-07-22 05:39:55

标签: vue.js

我正在尝试使用空new Vue实例创建一个事件总线。该应用程序足够大,可以拆分为多个组件文件。例如,我的应用程序的结构如下:

main.js

import Vue from vue;  
window.bus = new Vue();
Vue.component('update-user', require('./components/update-user');
Vue.component('users-list', require('./components/users-list');
Vue.component('edit-user', require('./components/edit-user');
Vue.component('user-address', require('./components/user-address');

new Vue({
    el:'body',
    ready(){

    }
}); 

组件/更新user.js的

export default{
    template: require('./update-user.template.html'),
    ready(){
        bus.$emit('test-event', 'This is a test event from update-user');
    }
}

组件/用户-list.js

export default{
    template:require('./users-list.template.html'),
    ready(){
        bus.$on('test-event', (msg) => { console.log('The event message is: '+msg)});
        //outputs The event message is: This is a test event
    }

组件/编辑user.js的

export default{
    template:require('./edit-user.template.html'),
    ready(){
        bus.$on('test-event', (msg) => {console.log('Event message: '+msg)});
        //doesn't output anything
        console.log(bus) //output shows vue instance with _events containing 'test-event'
    }
}

组件/用户address.js

export default{
    template:require('./user-address.template.html'),
    ready(){  
        bus.$on('test-event', () => {console.log('Event message: ' +msg)}); 
        //doesn't output anything
        console.log(bus) //output shows vue instance with _events containing 'test-event'
    }
}  

的index.html

...
<body>
    <update-user>
        <users-list></users-list>
        <edit-user>
            <user-address></user-address>
        </edit-user>
    </update-user>
</body>
...

我的问题是,bus.$on为什么只在第一个子组件中工作?即使我从<users-list>删除了侦听器,其他所有组件都无法收听该事件,即console.log() with bus.$on<users-list> i.e. the immediate child component之下/之后的任何组件中都不起作用。
我错过了什么或我在哪里做错了? 如何使这个工作,以便任何深度的任何子组件都可以监听从根组件或层次结构中较高层的任何位置发出的事件,反之亦然?

3 个答案:

答案 0 :(得分:3)

我想出来并让它发挥作用。在这里发布以帮助打击这个问题的其他人。

实际上我在问题中提到的实现并没有错。当事件被触发时,我试图在一个尚未渲染的组件(v-如果条件为假)中侦听事件。所以一秒钟之后(事件被触发后)当组件被渲染时它无法监听事件 - 这是Vue中的预期行为(我在laracasts论坛上得到了回复)。

但是,我最终的实施方式略有不同(基于Cody Mercer的建议,如下所示:

import Vue from vue;

var bus = new Vue({});

Object.defineProperty(Vue.prototype, $bus, {
    get(){
        return this.$root.bus;
    }
});  

Vue.component('update-user', require('./components/update-user');
Vue.component('users-list', require('./components/users-list');
Vue.component('edit-user', require('./components/edit-user');
Vue.component('user-address', require('./components/user-address');

new Vue({
    el:'body',
    ready(){

    },
    data:{
       bus:bus
    }
});   

现在要从任何组件访问事件总线,我可以使用this.$bus作为

this.$bus.$emit('custom-event', {message:'This is a custom event'});  

我可以从任何其他组件中听取此事件,例如

this.$bus.$on('custom-event', event => {
    console.log(event.message);  
    //or I can assign the message to component's data property  
    this.message = event.message;  

    //if this event is intended to be handled in other components as well
    //then as we normally do we need to return true from here  
    return true;
});

答案 1 :(得分:1)

触发侦听器时,事件传播停止。如果您希望事件继续,请从听众处返回true

https://vuejs.org/api/#vm-dispatch

bus.$on('test-event', () => {
  console.log('Event message: ' +msg); 
  return true;
}); 

答案 2 :(得分:0)

$emit在实例范围内调度事件 - 它不会传播给父母/子女。 $broadcast将传播到子组件。正如@Jeff的回答中所提到的,中间组件事件回调必须返回true以允许事件继续级联到[他们的]子项。

&#13;
&#13;
        
var child = Vue.extend({
  template: '#child-template',
  data: function (){
  	return {
    	notified: false
    }
  },
  events: {
  	'global.event': function ( ){
    	this.notified = true;
      return true;
    }
  }
});

var child_of_child = Vue.extend({
  data: function (){
    return {
      notified: false
    }
  },
  template: '#child-of-child-template',
  events: {
  	'global.event': function ( ){
    	this.notified = true;
    }
  }
});

Vue.component( 'child', child );
Vue.component( 'child-of-child', child_of_child );

var parent = new Vue({
    el: '#wrapper',
    data: {
      notified: false
    },
    methods: {
    	broadcast: function (){
        this.$broadcast( 'global.event' );
      },
      emit: function (){
        this.$emit( 'global.event' );
      }
    },
    events: {
    	'global.event': function (){
      	this.notified = true;
      }
    }
});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<div id="wrapper">
  <h2>Parent notified: {{ notified }}</h2>
  <child></child>
  <button @click="broadcast">$broadcast</button>
  <button @click="emit">$emit</button>
</div>

<template id="child-template">
  <h5>Child Component notified: {{ notified }}</h5>
  <child-of-child></child-of-child>
</template>
<template id="child-of-child-template">
  <h5>Child of Child Component notified: {{ notified }}</h5>
</template>
&#13;
&#13;
&#13;