【问题标题】:How to use a global event bus in vue.js 1.0.x?如何在 vue.js 1.0.x 中使用全局事件总线?
【发布时间】:2016-07-22 05:39:54
【问题描述】:

我正在尝试使用空的 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(){

    }
}); 

组件/update-user.js

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

组件/用户列表.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
    }

components/edit-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'
    }
}

组件/用户地址.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 只在第一个子组件中工作?即使我从&lt;users-list&gt; 中删除侦听器,其他组件都无法侦听该事件,即console.log() with bus.$on&lt;users-list&gt; i.e. the immediate child component 下方/之后的任何组件中都不起作用。
我错过了什么或者我做错了什么?
如何让它工作,以便任何深度的任何子组件都可以监听从根组件或层次结构中更高位置发出的事件,反之亦然?

【问题讨论】:

    标签: vue.js


    【解决方案1】:

    我想通了,让它工作了。在这里发帖是为了帮助其他遇到这个问题的人。

    其实我在上面的问题中提到的实现并没有错。当事件被触发时,我试图在尚未呈现的组件中侦听事件(v-if 条件为假)。所以一秒钟后(在事件被触发之后),当组件被渲染时它无法监听事件 - 这是 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;
    });
    

    【讨论】:

      【解决方案2】:

      当监听器被触发时,事件传播停止。如果您希望活动继续进行,只需从您的听众处返回 true

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

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

      【讨论】:

      • 是的,我知道,所以我从&lt;users-list&gt; 组件中删除了侦听器,但它仍然不起作用,我的意思是即使我从第一个直接子项(即&lt;users-list&gt;)中删除侦听器并拥有第二个直接子节点的侦听器,即&lt;edit-user&gt;,这里的事件侦听器没有捕获事件并响应,即console.log('Event message: '+msg)不;在&lt;edit-user&gt;中不输出任何内容。
      • 我什至尝试使用$broadcast 来发出事件。顺便说一句,&lt;edit-user&gt; 组件只有在从&lt;users-list&gt; 中进行选择后才会被实例化。
      • 当我在玩的时候,我将事件发出在 setTimeout() 中作为 setTimeout(() =&gt; {bus.$emit('test-event', 'This is a test event from update-user');}, 5000) 包装在 &lt;update-user&gt; 组件中,然后从满足 &lt;users-list&gt; 组件中进行选择 @987654335 @&lt;edit-user&gt; 的条件,所以它在事件发出之前就被实例化了。现在我可以捕获事件并将消息记录到控制台。
      • 这意味着不在当前范围内的组件(即尚未实例化)将无法捕获在实例化之前发出的事件,即使事件仍然存在于总线中 - 是我的理解正确吗?
      【解决方案3】:

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

              
      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;
            }
          }
      });
      <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>

      【讨论】:

      • 我正在尝试使用单独的空 Vue 实例作为事件总线,所以我认为 $broadcast / $dispatch /$emit 不会有任何区别,因为就 bus vm 而言,没有孩子.如果不是这样,请告诉我。另外请看一下我对杰夫的回答和建议的cmets。谢谢
      猜你喜欢
      • 2016-10-30
      • 1970-01-01
      • 2017-04-25
      • 1970-01-01
      • 2022-01-23
      • 2018-07-07
      • 2020-12-07
      • 2015-06-20
      • 2019-08-19
      相关资源
      最近更新 更多