You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法移除EventListener:TypeScript中鼠标移动事件监听删除失败

鼠标指针锁定解除后无法移除mousemove监听器的问题解决

你的问题核心在于**Function.prototype.bind()每次调用都会返回一个全新的函数实例**。你在注册监听器时用了this._handleMouseMovement.bind(this),解除锁定时又调用了一次相同的bind语句——这两个函数看起来功能一样,但在内存里是完全不同的引用,所以removeEventListener找不到要移除的那个监听器,导致它一直生效。

解决方案:提前绑定并复用函数引用

我们可以在类的构造函数里提前把_handleMouseMovement绑定好上下文,存为一个实例属性,之后注册和移除监听器都用这个属性,保证引用一致。

修改后的代码如下:

class MyClass { 
    let canvas: any;
    // 新增:存储绑定好上下文的处理函数
    private _boundMouseMovementHandler: (event: MouseEvent) => void;

    constructor(canvas: any) { 
        this.canvas = canvas;
        // 提前绑定并保存函数引用
        this._boundMouseMovementHandler = this._handleMouseMovement.bind(this);
        this.canvas.onclick = this._mouseClickHandler.bind(this); 
        document.addEventListener('pointerlockchange', this._togglePointerLock.bind(this), false); 
    } 

    private _mouseClickHandler(event: MouseEvent): void { 
        this.canvas.requestPointerLock(); 
    } 

    private _togglePointerLock() { 
        if (document.pointerLockElement === this.canvas) { 
            console.info('Locked mouse pointer to canvas.'); 
            // 使用提前绑定好的函数引用
            document.addEventListener('mousemove', this._boundMouseMovementHandler, false); 
        } else { 
            console.info('Unlocked mouse pointer from canvas.'); 
            // 移除时用同一个引用
            document.removeEventListener('mousemove', this._boundMouseMovementHandler, false); 
        } 
    } 

    private _handleMouseMovement(event: MouseEvent) { 
        console.log('Mouse moved to: ', event.movementX, event.movementY); 
    } 
} 

额外优化提示

你原来代码里的这两行其实是多余的,可以删掉:

this.canvas.requestPointerLock = this.canvas.requestPointerLock;
document.exitPointerLock = document.exitPointerLock;

这两个方法本来就是DOM元素和document的原生方法,重新赋值不会有任何作用,反而会增加代码冗余。

内容的提问来源于stack exchange,提问作者チーズパン

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:33:43