Web 3D设计[Three.js]关于右键点击Canvas旋转模型,在其他元素上触发右键菜单问题

问题

3D项目中使用Three.js设计模型,功能设计为右键旋转模型,所以直接禁用了右键菜单。

在3D场景上面,定位了些toolbar工具界面.

现在出现的问题是,在3D场景中,右键按下旋转模型,鼠标旋转时如果在工具界面,或者任务栏,松开右 键,会直接触发右键菜单。

在任务栏会触发任务栏设置,任务栏管理器等菜单。

过程

方法1 、添加全局右键e.button === 2菜单阻止 e.preventDefault();e.stopPropagation(); 。结果无效。

方法2 、在TrackballControls 控制器中监听右键的mousedownmouseup, 禁用。 结果无效。

方法3、在Vue全局禁用右键,太偏激,放弃。

方法4、添加鼠标事件跟踪,跟踪右键按下状态 ,按下禁止,抬起时检测是否在canvas上。结果无效。

解决办法

核心解决方案:使用 setPointerCapture
setPointerCapture 可以将后续所有的鼠标/触控事件"锁定"在 Canvas 元素上,即使你的鼠标移出了 Canvas,移到了工具栏上,甚至移到了浏览器窗口之外(在大多数现代浏览器中),松开鼠标的事件依然会被 Canvas 接收,而不是被底下的元素接收。

javascript 复制代码
function initHelpers() {
    if (!camera.value || !renderer.domElement) {
        console.error('初始化控制器失败:缺少相机或渲染器DOM元素');
        return;
    }

    const canvas = renderer.domElement;
    controls = new TrackballControls(camera.value, canvas);
    controls.rotateSpeed = 7.0; 
    controls.zoomSpeed = 1.5;   
    controls.panSpeed = 1.0;   
    controls.noZoom = false;
    controls.noPan = false;
    controls.staticMoving = true;
    controls.dynamicDampingFactor = 0.1;
    controls.target.set(75, 0, 0);
    controls.update(); 

    // 禁用控制器默认的右键逻辑
    controls.mouseButtons = {
        LEFT: THREE.MOUSE.NONE,      
        MIDDLE: THREE.MOUSE.PAN,     
        RIGHT: THREE.MOUSE.ROTATE,   
    };

    // ============================================================
    // 👇👇👇在这里 👇👇👇
    // ============================================================

    // 定义一个状态标记:是否正在(或刚刚结束)右键拖拽
    let isRightDragging = false;

    const handlePointerDown = (event) => {
        if (event.button === 2) { // 右键
            isRightDragging = true; // 标记开始
            try {
                canvas.setPointerCapture(event.pointerId); // 锁定鼠标
            } catch (e) {
                console.warn(e);
            }
        }
    };

    const handlePointerUp = (event) => {
        if (event.button === 2) { // 右键
            try {
                canvas.releasePointerCapture(event.pointerId); // 释放锁定
            } catch (e) {}

            // 【关键点】:不要立即将 isRightDragging 设为 false
            // 浏览器触发顺序通常是:mouseup -> contextmenu
            // 我们延迟 100ms 重置状态,覆盖掉 contextmenu 触发的时间窗口
            setTimeout(() => {
                isRightDragging = false;
            }, 100);
        }
    };

    // 注册捕获阶段事件 (Capture Phase)
    canvas.addEventListener('pointerdown', handlePointerDown, { capture: true });
    canvas.addEventListener('pointerup', handlePointerUp, { capture: true });

    // 全局拦截右键菜单
    // 只要 isRightDragging 为 true (包含松开后的那100ms),就坚决禁止菜单
    const preventGlobalContextMenu = (event) => {
        if (isRightDragging) {
            event.preventDefault();
            event.stopPropagation(); // 阻止冒泡,防止上层 UI 接收到
            return false;
        }
    };
    window.addEventListener('contextmenu', preventGlobalContextMenu, { capture: true });
    canvas.addEventListener('contextmenu', (e) => e.preventDefault());

    // ============================================================
    // 👆👆👆 代码结束 👆👆👆
    // ============================================================

    // View helper
    helper = new ViewHelper(camera.value, renderer.domElement);
    // ...
}

就这样。

相关推荐
酒鼎26 分钟前
学习笔记(12-02)事件循环 - 实战案例 —⭐
前端·javascript
Bigger31 分钟前
第一章:我是如何剖析 Claude Code 整体架构与启动流程的
前端·aigc·claude
小恰学逆向36 分钟前
【爬虫JS逆向之旅】某球网参数“md5__1038”逆向
javascript·爬虫
竹林81837 分钟前
从“连接失败”到丝滑登录:我用 ethers.js v6 搞定 MetaMask 钱包连接的全过程
前端·javascript
oi..41 分钟前
《Web 安全入门|XSS 漏洞原理、CSP 策略与 HttpOnly 防护实践》
前端·网络·测试工具·安全·web安全·xss
UXbot1 小时前
2026年AI全链路产品开发工具对比:5款从创意到上线一站式平台深度解析
前端·ui·kotlin·软件构建·swift·原型模式
一拳不是超人1 小时前
前端工程师也要懂的服务器部署知识:从 Nginx 到 CI/CD
服务器·前端
AlkaidSTART1 小时前
TanStack Query 技术指南:异步状态管理核心实践
前端·react.js
前端那点事1 小时前
前端必看!JS高频实用案例(单行代码+实战场景+十大排序)
javascript
种花家的强总1 小时前
前端项目开发/维护中降低成本的方式之一:降低耦合度
前端