Three.js中DOM动态添加按钮点击事件无效问题求助
Three.js中OrbitControls导致标注菜单按钮点击失效的解决方法
问题描述
我尝试在Three.js场景的左侧/右侧上方创建标注菜单,编写了如下代码:
function performAnnotation(event: MouseEvent) { console.log(event) console.log('hello') } function loadAnnotationIntoScene() { const menuPanel = document.getElementById('menu-panel') as HTMLDivElement const _menuList = document.createElement('ul') as HTMLUListElement menuPanel.appendChild(_menuList) annotation.forEach((element, index) => { const myList = document.createElement('li') as HTMLLIElement const _list = _menuList.appendChild(myList) const myButton = document.createElement('button') as HTMLButtonElement myList.appendChild(myButton) myButton.classList.add('annotationButton') myButton.innerHTML = element['text'] myButton.addEventListener('click', performAnnotation, false) }) }
这段代码在JSFiddle中测试完全正常,但在使用OrbitControls的Three.js项目中,绑定了事件监听器的按钮无法触发点击事件,推测是OrbitControls的事件冲突导致的。
场景截图:
简化测试代码:
function performAnnotation(event) { console.log("hello") } const annotation = [1, 2, 3, 4] function loadAnnotationIntoScene() { const menuPanel = document.getElementById('menu-panel') const _menuList = document.createElement('ul') menuPanel.appendChild(_menuList) annotation.forEach((element, index) => { const myList = document.createElement('li') const _list = _menuList.appendChild(myList) const myButton = document.createElement('button') myButton.innerHTML = "hello" myList.appendChild(myButton) myButton.addEventListener('click', performAnnotation, false) }) } loadAnnotationIntoScene()
<div id="menu-panel"></div>
可行解决方案
1. 阻止事件冒泡到Three.js画布
OrbitControls会监听画布的鼠标事件,导致DOM元素的点击事件被拦截。给菜单按钮或容器添加事件阻止冒泡,让事件优先被DOM元素捕获:
// 给单个按钮添加 myButton.addEventListener('click', (e) => { e.stopPropagation(); // 阻止事件冒泡到画布 performAnnotation(e); }, false); // 或者给整个菜单容器添加,一次性解决所有子元素问题 const menuPanel = document.getElementById('menu-panel'); menuPanel.addEventListener('click', (e) => { e.stopPropagation(); });
2. 限制OrbitControls的事件监听范围
默认OrbitControls会绑定到整个document,修改为只绑定到Three.js的渲染画布,这样画布外的DOM元素事件不受影响:
// 获取你的Three.js渲染画布 const canvas = document.querySelector('canvas'); // 初始化OrbitControls时指定domElement为画布 const controls = new OrbitControls(camera, canvas);
3. 确保菜单DOM层级高于画布
检查CSS设置,保证菜单容器的z-index值足够大,避免被画布遮挡:
#menu-panel { position: absolute; top: 20px; left: 20px; z-index: 100; /* 数值大于画布的z-index即可,画布默认一般为0 */ background: #fff; padding: 10px; }
内容的提问来源于stack exchange,提问作者Pravin Poudel
相关产品推荐
相关产品推荐

