为什么我的Nuxt应用中removeEventListener没有正常生效?
问题根因
该报错由两个资源泄漏问题共同导致:
- MutationObserver未被正确清理:组件销毁时没有断开observer的监听,只要原监听的DOM节点发生变更,就会触发
mountOnScroll回调,重复给window绑定已销毁组件的handleScroll方法。此时已销毁组件的$refs.scrollComponent已被回收,访问getBoundingClientRect就会抛出undefined错误。 - 滚动事件重复绑定且无空值判断:你在
mounted和mountOnScroll中都会绑定scroll事件,但unmounted中仅移除一次,多出来的泄漏事件在组件销毁后仍然会被触发,且handleScroll中没有对DOM节点做空值兜底。
修复方案
按如下步骤修改代码即可解决:
- 将MutationObserver实例挂载到组件实例上,组件销毁时主动断开监听
- 绑定scroll事件前先移除已有的同类型监听,避免重复绑定
- 在
handleScroll中增加DOM节点的空值判断,避免异常调用 - 所有访问
$refs的位置都先做存在性校验,避免DOM未挂载时的报错
修复后完整代码
<template> <div class="grid-card-layout scrolling-component" ref="scrollComponent"> <slot/> </div> </template> <script> export default { methods: { handleScroll() { const element = this.$refs.scrollComponent // 节点不存在直接退出逻辑 if (!element) return if (element.getBoundingClientRect().bottom < window.innerHeight) { window.removeEventListener('scroll', this.handleScroll); return this.$emit("load-more"); } }, mountOnScroll() { // 先移除再绑定,避免重复注册 window.removeEventListener('scroll', this.handleScroll); window.addEventListener('scroll', this.handleScroll); } }, mounted() { this.mountOnScroll() // 存储observer实例方便后续清理 this.domObserver = new MutationObserver(this.mountOnScroll); if (this.$refs.scrollComponent) { this.domObserver.observe(this.$refs.scrollComponent, { attributes: true, childList: true, characterData: true }); } }, unmounted() { // 清理滚动事件监听 window.removeEventListener('scroll', this.handleScroll); // 断开MutationObserver,彻底清理泄漏源 if (this.domObserver) { this.domObserver.disconnect(); this.domObserver = null } } } </script>
补充说明
如果你的组件开启了<keep-alive>缓存,还需要额外在activated钩子中重新绑定事件和observer,在deactivated钩子中提前清理监听,避免缓存切换时的同类报错。
内容的提问来源于stack exchange,提问作者Opeyemi Odedeyi
相关产品推荐
相关产品推荐

