【问题标题】:Vue.js method called multiple times using $emit and $on when it should only be called onceVue.js 方法使用 $emit 和 $on 多次调用,而它应该只调用一次
【发布时间】:2017-06-12 07:12:51
【问题描述】:

我正在使用总线以允许组件通过此链接中描述的方法与其他组件交互:https://forum.vuejs.org/t/create-event-bus-in-webpack-template/4546/2

我有一个在创建的钩子中调用的方法,它使用总线发出事件。

created () {
  this.getReviewDeck()
},
myMethod () {
    bus.$emit('increment')
}

在另一个组件(包含在上述组件中)中,我将事件侦听器附加到创建的挂钩中,如下所示:

created () {
  bus.$on('increment', this.incrementCount)
},
incrementCount () {
  console.log('count incremented')
}

如果我第一次访问该组件,一切正常,控制台将记录一次“计数递增”。但是,如果我离开该组件,然后在下次“计数递增”时导航回它,将被记录两次,如果我离开并再次返回,它现在将被记录三次,等等。

我不太清楚到底发生了什么或如何最好地解决这个问题,这样每次我访问组件时,消息只会记录一次而不是多次。

【问题讨论】:

  • 如何设置总线?也许你多次定义它?我通常在应用程序的引导程序中将总线添加到 Vue 组件原型中。这将确保您不会多次定义它。作为第一个“调试步骤”,您应该在您创建的方法中进行控制台日志,您在总线上注册以检查它被调用的频率。它应该只被调用一次。
  • “离开/访问组件”是什么意思?

标签: vuejs2 vue-component vue.js


【解决方案1】:

移除所有监听器:

this.$eventBus.$off()

将此添加到您的主要组件生命周期的 beforeDestroy() 事件中。

beforeDestroy() {
   this.$bus.$off('chatData');
}

【讨论】:

    【解决方案2】:

    似乎在 Vue 源代码中发生了一些变化,因为在 destroy 或 beforeDestroy 或 beforeRouteLeave 或任何其他挂钩中关闭 eventBus 侦听器会执行以下操作 - 旧侦听器与在 created 挂钩中重新注册的新侦听器一起被删除。

    对于destroyed 和beforeDestroy 钩子,这是可以理解的,因为它们是在created 钩子之后调用的。因此 created() 添加了监听器,并且 destroy() 将它们全部删除,而不仅仅是之前 created() 中的监听器。但是对于路由挂钩,我不理解这种行为,因为它们是在 created() 之前调用的,但是所有相同的重新注册的侦听器都不起作用。

    我所做的是在重新注册之前关闭已创建挂钩中的 eventBus 侦听器

    created() {
      eventBus.$off("someListener");
      eventBus.$on("someListener", () => {
        // do smth
      })
    }
    

    但这只有在组件被重新创建时才有效,它在应用程序生命周期中只创建一次,注册的监听器将不起作用。但是如果组件创建一次我们就不需要这个重新注册了。

    【讨论】:

      【解决方案3】:

      我遇到了类似的问题,上面提到的答案都不适合我。 我通过将 eventBus 添加为 Vue 全局实例解决了这个问题

      在 main.js 文件中添加这个

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

      并在组件中调用它,例如:

         mounted(){
          this.$bus.$on('chatData', (data) => {
              console.log('receieved in component');
          });
         },
         beforeDestroy() {
          this.$bus.$off('chatData');
         },
         methods:{
          sendData(data){
           this.$bus.$emit('someData',data); 
          }
         }
      

      【讨论】:

      • 这对我也有用。虽然上述解决方案是正确的,但在我的情况下,我并没有离开组件,所以 beforeDestroy 不相关并且事件仍然触发了两次甚至更多......
      • 所以你没有关闭事件吗?
      • 添加事件作为你提到的 Vue 全局实例对我有帮助剩下...
      【解决方案4】:

      这适用于如果您只想在事件发出后执行一次操作的情况。如果您想继续侦听某个事件,例如:如果您将鼠标悬停在图表上的某个数据点上,您想触发其他组件的某些操作,该怎么办。 在这种情况下,使用 $once 不起作用。 我面临着同样的问题,我在悬停时发出一个事件并使用 $on 订阅它,它应该只被调用一次,但在我的情况下它被多次调用。

      这就是我发出事件的方式;

      this.$eventBus.$emit("SHOW_HOVERLINE", d);
      

      这就是我订阅活动的方式;

      this.$eventBus.$on("SHOW_HOVERLINE", this.someFunction);
      

      【讨论】:

      • 如果您有新问题,请点击 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。 - From Review
      • 当然。我会将其添加为问题
      【解决方案5】:

      你可以使用 $.once

      created () {
        bus.$once('increment', this.incrementCount)
      },
      

      【讨论】:

        【解决方案6】:

        必须在销毁时删除事件处理程序。

         beforeDestroy () {
            EventBus.$off('increment', this.incrementCount)
         },
        

        【讨论】:

        • 不知何故@dpst的解决方案在我的情况下效果不佳,一旦我将bus.$off添加到beforeDestory,它就会触发固定三次。这时候我只是在函数末尾加了bus.$off,收工了。
        • 在我自己的项目中,我使用了destroyed 事件而不是beforeDestroy
        • 我认为这个链接上的帖子应该和这个答案一起阅读。这是对重复事件侦听器问题的一个很好的解释(为了更好地理解):charlietheprogrammer.com/…
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-06
        • 2019-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多