从 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 组件发出的重复事件的主要内容,如果未能解决你的问题,请参考以下文章