动态组件事件总线无法在vue中运行?

时间:2018-05-15 07:32:19

标签: vue.js vuejs2 vuex

我刚刚在vuejs中使用事件总线来获取动态组件,但是当我从一个组件发出事件时,我无法在另一个组件中侦听该事件。下面是我通过codesandbox创建的演示,我想要做的是在tes2'中输出' test来自test2component,但它什么也没输出。但是当我在HomeCompnent中取消注释$ bus监听器时,两个console.log都被执行了。

main.js

Vue.propotype.$bus = new Vue();

HomeComponent

<template>
  <div>
    <component :is="currentComponent" @changeComponent="changeComponent"></component>
  </div>
</template>

<script>
import Test1Component from "./Test1Component";
import Test2Component from "./Test2Component";

export default {
  created() {
    // this.$bus.$on("test", () => console.log("event bus test"));
  },
  components: {
    Test1Component,
    Test2Component
  },
  data() {
    return {
      currentComponent: "Test1Component"
    };
  },
  methods: {
    changeComponent() {
      this.currentComponent = "Test2Component";
    }
  }
};
</script>

<style>

</style>

Test1Component

<template>
  <div>
    <h1>test1</h1>
    <button @click="changeComponent">click me</button>
  </div>
</template>

<script>
export default {
  methods: {
    changeComponent() {
      this.$emit("changeComponent");
      this.$bus.$emit("test");
    }
  }
};
</script>

<style>

</style>

Test2Component

<template>
  <h1>test2</h1>
</template>

<script>
export default {
  created() {
    this.$bus.$on("test", () => console.log("test in test2"));
  }
};
</script>

<style>

</style>

Edit Vue Template

3 个答案:

答案 0 :(得分:2)

事件总线很好,但问题在于实施。

你是非常正确的un-comment code在家庭组件中,我在你的代码片段上测试它只发出一次event bus test [console.log]

  

您需要注意事件

  1. 您需要定义侦听器。 [确保在发出事件之前定义它们]
  2. 现在你只发出一个事件。 [工作我们需要听众先听]
  3. 在您的情况下,您在listener function $on

    created事件中撰写了Test2Component

    现在就想想,开始时你没有任何听众,就像home compo你刚刚评论过听众代码一样。[它的第一步]

    现在,当您单击click me按钮时,您changing组件到新组件[Test2Component],它已挂载且其created事件将触发then this listener will start listening to event

    但你错过了

    this.$emit("changeComponent"); // this is first [ fires/emit ]
    this.$bus.$emit("test"); // THEN THIS EMIT
    
      

    所以,当它刚从changing compo2 compo1 to测试同步fired/emitted directly without wait, its not A 同步{{ 1}} {changeComponent {1}} test`]

    猜猜什么现在it is发出时,It will not wait to finish all stuff of. It will be emitted immediately [已发出

      

    所以,test,所以没有Dom operation to add component, ITS NOT DONE YET

    但是,如果您看到,test之前家庭功能监听器中的No listeners are there已经很好地定义,那么它将在控制台中输出。

    我希望你理解它,如果不是让我知道,我会详细解释它

      

    另一个问题是您在console.log中添加了$ bus,因此所有组件都有自己的总线。相反,您可以使用UNCOMMENT listener

    例如你可以看到。

    在es6中你可以做到

    emit of test event

    将其导入其他组件

    prototype

    &#13;
    &#13;
    GLOBAL event Bus
    &#13;
    //bus.js
    const bus = new Vue({});
    export default bus;
    
    &#13;
    &#13;
    &#13;

答案 1 :(得分:1)

这个问题很好地证明了事件总线模式的缺点:

开发人员必须小心确保所有事件的发件人和收件人在同一时刻确实存在。

在您的方案中,情况并非如此:

  • 当Test1Component发出事件时,Test2Component尚未存在。
  • 在HomeComponent刚刚创建了Test2Component之后,该事件已经过去了#34;。

我作为Vue核心团队成员的通常免责声明:不要使用事件总线模式。

答案 2 :(得分:0)

您的测试不正确。

基本上,在Test2Component发出Test1Component

的时间内未创建this.$bus.$emit("test");

您看到2个console.log,因为codesandbox使用热重装模块,因此如果您更改代码,this.$bus.$on("test", () => console.log("test in test2"));仍会注册。

如果在Test2Component中销毁组件时取消注册,test in test2永远不会被记录

<强> Test2Component.vue

<template>
  <div>
    <h1>test2</h1>
    <button @click="changeComponent">click me</button>
  </div>
</template>

<script>
export default {
  created() {
    console.log("Component 2 is created");
    this.$bus.$on("test", this.testLog);
  },
  beforeDestroy() {
    this.$bus.$off("test", this.testLog);
  },
  methods: {
    testLog() {
      console.log("test in test2");
    },
    changeComponent() {
      this.$emit("changeComponent");
    }
  }
};
</script>
<style>

</style>

演示:https://codesandbox.io/s/2485jw460y

如果您发表评论

  beforeDestroy() {
    this.$bus.$off("test", this.testLog);
  },

在组件2中,您会看到test in test2在点击几下后多次打印

(如果您更改了代码,请刷新以便从头开始运行)