从 VueJS 组件发出的重复事件

Posted

技术标签:

【中文标题】从 VueJS 组件发出的重复事件【英文标题】:Duplicate events being emitted from VueJS component 【发布时间】:2018-12-29 15:05:24 【问题描述】:

当我的鼠标光标进入和离开我的 VueJS 组件时,会分别调用以下方法。

光标进入和离开我的组件时调用的方法:

// located in "methods" section of my Vue component file

onMouseEnter() 
    window.Event.$emit("mouse-entered", this.index);
    console.log("Mouse entered");
,
onMouseLeave() 
    window.Event.$emit("mouse-left", this.index);
    console.log("Mouse left");
,

当我的光标进入和离开组件时,这就是我的控制台的样子(每次都会发出一个事件):

然而,真正奇怪的是,在 Vue 开发工具中,每次我的光标进入和离开我的组件时,我都会看到重复的事件

鉴于这些相互矛盾的信息,我不确定该相信什么。 有时刷新页面可以消除开发工具中的重复事件,但我总是在我的控制台中获得单一、独特的事件,这是我想要的行为。

有谁知道这里发生了什么,我应该接受什么作为真相的来源?

以下是在 main.js 文件中声明和初始化 Vue 实例的方式:

// As far as I can tell, duplicated Vue instances are not being created here on page refresh

let app;

// global event bus
window.Event = new Vue();
console.log("Event bus created");

/* This section ensures the firebase auth object isn't in an intermediary state. */
firebase.auth().onAuthStateChanged(() => 
    if (!app) 
        console.log("New Vue instance created");
        app = new Vue(
            el: '#app',
            router,
            store,
            render: h => h(App)
        );
    
);

请注意,这个特定的组件在两条不同的路线(“dashboard”和“home”)上重复使用,它们都通过以下代码保持活动状态。

// Template section of App.vue file
<template>
    <div id="app">
        <keep-alive
            v-bind:include="[ 'dashboard', 'home' ]"
            <router-view></router-view>
        </keep-alive>
    </div>
</template>

此外,由于这两条路由一直保持活动状态并被缓存,未能关闭 $off 事件发射器和侦听器不应该是重复的原因(至少我认为不应该)。

编辑 1: 我在项目的每个目录中都查找了“mouse-entered”和“mouse-left”,我可以确认这两个事件仅从 Vue 发出我在这篇文章中提到的组件。

编辑 2: 为了帮助调试,我在最顶层的组件 (App.vue) 上放置了一个侦听器,以查看它是否接收到两次事件(请参阅代码中创建的挂钩下面的sn-p)。 我可以确认它也只接收一次事件。我也粘贴在我完整的 App.vue 文件中,因为上面的示例主要是为了说明我正在保持“仪表板”和“主页” ”。

<template>
    <div id="app">
        <keep-alive
            v-bind:include="keepAlive">
            <router-view></router-view>
        </keep-alive>
    </div>
</template>

<script>
    export default 
        name: 'app',
        data() 
            return 
                isLoggedIn: false,
            ;
        ,
        computed: 
            keepAlive() 
                if (this.isLoggedIn) 
                    return [ 'dashboard', 'home', 'results' ];
                
                return [ 'landing', 'signIn', 'signUp' ];
            
        ,
        watch: 
            /* This watches for route changes */
            $route(to, from) 
                /* firebase.auth().currentUser returns null if user has logged out */
                if (firebase.auth().currentUser) 
                    this.isLoggedIn = true;
                 else 
                    this.isLoggedIn = false;
                
            
        ,
        created() 
            window.Event.$on("mouse-entered", () => 
                console.log("mouse-entered-from-App.vue");
            );
            window.Event.$on("mouse-left", () => 
                console.log("mouse-left-from-App.vue");
            );
        
    ;
</script>

正如预期的那样,App.vue 接收到一次事件(见下文);但是,我仍然在 Vue 开发工具中收到重复事件:(

【问题讨论】:

这绝对是奇怪的。也许没有必要,但是您是否仔细检查过代码中其他地方没有任何mouse-entered 事件,而没有console.log 可以以某种方式触发?您是否能够通过导航始终如一地获得这种行为?还是涉及编辑和保存您的代码? @Sumurai8 我可以确认在我的项目目录中查找所有内容后,其他组件永远不会发出事件。当我导航到其他路线并返回到该组件所在的路线(仪表板和主页)时,它总是会发生。此外,事件只会重复,永远不会重复。 我真的想不出事件会触发的情况,但控制台消息不会被复制,所以你可以尝试在最顶层的组件上放置一个监听器,看看是否 that 接收事件两次。如果没有,我认为可以肯定地说 vue devtools 有一个错误。否则我们需要进一步观察。 @Sumurai8 我在 App.vue 上放了一个监听器,我可以确认它只接收一次事件,但我仍然会在开发工具中收到重复的事件。我还添加了我的整个 App.vue 代码,这对我来说看起来不错,但可能会向其他人透露一些东西。 只要事件仅被有效触发一次(例如控制台日志记录),开发工具中显示的内容无关紧要,您的程序应该可以工作。不是吗? .. 这可能是 vue-devtools 中的错误。也许是一些隐藏的事件冒泡? 【参考方案1】:

你写的

刷新页面有时会消除开发工具中的重复事件,但我总是在我的控制台中获得单个、独特的事件,这是我想要的行为。

按照您描述问题的方式,事件是正确发出的,而它们的反应却是错误的、重复的方式。 我认为您可能缺少的是在组件被销毁后取消订阅事件总线。您应该使用 beforeDestroy 挂钩来执行此操作(类似于您在组件生命周期中早些时候使用 created 订阅的方式)。

类似这样的:

beforeDestroy() 
    window.Event.$off('mouse-entered');
    window.Event.$off('mouse-left');

【讨论】:

以上是关于从 VueJS 组件发出的重复事件的主要内容,如果未能解决你的问题,请参考以下文章

Vuejs 3 从子组件向父组件发出事件

在 VueJS 中调度后如何发出事件?

发出的事件不会调用 Vue JS 组件中的父方法

有没有办法从VueJS中的父级触发组件方法?

Vuejs 中从子级到父级的事件监听

从 VueJS 中的事件传递数据