You need to enable JavaScript to run this app. 为什么我的Nuxt应用中removeEventListener没有正常生效?
优惠活动
大模型
产品
解决方案
定价
更多

为什么我的Nuxt应用中removeEventListener没有正常生效?

问题根因

该报错由两个资源泄漏问题共同导致:

  • MutationObserver未被正确清理:组件销毁时没有断开observer的监听,只要原监听的DOM节点发生变更,就会触发mountOnScroll回调,重复给window绑定已销毁组件的handleScroll方法。此时已销毁组件的$refs.scrollComponent已被回收,访问getBoundingClientRect就会抛出undefined错误。
  • 滚动事件重复绑定且无空值判断:你在mounted和mountOnScroll中都会绑定scroll事件,但unmounted中仅移除一次,多出来的泄漏事件在组件销毁后仍然会被触发,且handleScroll中没有对DOM节点做空值兜底。

修复方案

按如下步骤修改代码即可解决:

  1. 将MutationObserver实例挂载到组件实例上,组件销毁时主动断开监听
  2. 绑定scroll事件前先移除已有的同类型监听,避免重复绑定
  3. 在handleScroll中增加DOM节点的空值判断,避免异常调用
  4. 所有访问$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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 00:51:01