Vue 单页面应用中,不要在 onMount 里添加事件监听器!

234 阅读3分钟

大家好,我是宝哥。

在开发Vue单页面应用时,我们经常会遇到需要在组件中添加事件监听器的情况。然而,如果不正确地管理这些监听器,就可能引发一些棘手的问题,比如事件触发次数异常增加。本文将分享一次我在项目中遇到的事件监听器堆叠问题,以及我是如何通过几种策略来解决这个问题的。

引言

最近在为客户做一个项目时,需要在基于 Vue 的单页面应用 (SPA) 中集成一个事件监听器,该事件监听器用于一个名为 "HomeView" 的组件,该组件包含一个 iframe。这个事件,名为 "triggerEvent",最初是在 HomeViewonMount 生命周期钩子中设置的。这种设置会导致一个意想不到的行为:当你离开 HomeView 然后返回时,"triggerEvent" 会触发多次,表明事件监听器在堆叠。

问题分析

为了更好地理解这个问题,我尝试使用 location.replace() 而不是 router.push() 来进行导航。前者似乎解决了问题,这表明导航方法会影响事件监听器的行为。进一步测试 router.push() 证实,每次导航都会添加一个新的监听器,而不会移除之前的监听器,从而导致触发次数不断增加。

根本原因

这种行为源于像 Vue 这样的 SPA 框架如何管理事件监听器。在 Vue 中,使用 onMount 挂载的组件,在卸载时不会自动清理其事件监听器,除非在代码中显式地进行清理。因此,如果一个组件多次挂载,就像在 SPA 中使用 router.push() 进行导航(不进行完整的页面重新加载)时常见的情况,就会导致监听器重复。

解决方案

组件卸载时清理监听器

为了防止此问题,一个有效的策略是在组件卸载时移除事件监听器:

<template>
 <!-- Your component template -->
</template>

<script> import { onMounted, onUnmounted } from 'vue';

export default {
 setup() {
   const handleEvent = () => console.log('Event triggered');
   onMounted(() => window.addEventListener('triggerEvent', handleEvent));
   onUnmounted(() => window.removeEventListener('triggerEvent', handleEvent));
 }
}; </script>`
   

条件事件监听器绑定

另一种方法是在添加新的监听器之前检查是否已存在监听器,从而防止重复:

<template>
 <!-- Your component template -->
</template>

<script> import { onMounted, ref } from 'vue';

const eventBound = ref(false);

export default {
 setup() {
   const handleEvent = () => console.log('Event triggered');
   onMounted(() => {
     if (!eventBound.value) {
       window.addEventListener('triggerEvent', handleEvent);
       eventBound.value = true;
     }
   });
 }
}; </script>`
   

App.vue 中添加全局事件监听器

另一种方法是将事件监听器放在 App.vue 中,该组件只挂载一次,从而避免任何重新绑定问题:

<template>
 <div id="app">
   <!-- Your app template -->
 </div>
</template>

<script> import { onMounted } from 'vue';

export default {
 setup() {
   const handleEvent = () => console.log('Global event triggered');
   onMounted(() => window.addEventListener('triggerEvent', handleEvent));
 }
}; </script>`
   

总结

通过上述的探索和实践,我们可以看到,正确地管理事件监听器对于保持Vue单页面应用的稳定性和性能至关重要。无论是在组件卸载时进行清理,还是在添加之前检查监听器是否已存在,或是将监听器放在全局的App.vue中,这些策略都能有效地避免事件监听器的堆叠问题。希望这些经验能够帮助你在未来的Vue开发中避免类似的问题,让你的应用更加健壮和高效。

最后,如果你觉得宝哥的分享还算实在,就给我点个赞,关注一波。分享出去,也许你的转发能给别人带来一点启发。