THREE.js在iframe中WebGLRenderer画布getBoundingClientRect返回0,PAN事件失效如何解决?
问题:Three.js iframe中TrackballControls无法触发PAN事件,画布getBoundingClientRect返回全0
我编写了如下代码:
... renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(WIDTH, HEIGHT); ... controls = new TrackballControls(camera, renderer.domElement);
当代码在iframe中运行时,PAN事件无法触发。排查发现执行以下代码:
console.log('???', renderer.domElement.getBoundingClientRect())
返回结果为DOMRect {x: 0, y: 0, width: 0, height: 0, top: 0, …}。这会导致鼠标移动事件被映射至无穷大,因为触发resize事件前,画布没有有效宽高值。动态添加canvas到DOM时,传入TrackballControls这类插件容易出现时序错误,请问如何确保仅在画布实际加载完成后再使用它?
解决方案
1. 先将canvas添加到DOM再初始化控件
确保renderer.domElement已经挂载到DOM树中,再实例化TrackballControls,此时画布的布局尺寸已能正确计算:
// 先把canvas添加到页面DOM document.body.appendChild(renderer.domElement); // 再初始化TrackballControls controls = new TrackballControls(camera, renderer.domElement);
2. 循环检查画布尺寸,就绪后初始化控件
通过requestAnimationFrame循环检测画布的实际尺寸,直到宽高都大于0再初始化控件:
function initControls() { const rect = renderer.domElement.getBoundingClientRect(); if (rect.width > 0 && rect.height > 0) { controls = new TrackballControls(camera, renderer.domElement); // 可选:初始化后触发一次resize更新控件状态 window.dispatchEvent(new Event('resize')); } else { requestAnimationFrame(initControls); } } // 先将canvas添加到DOM document.body.appendChild(renderer.domElement); // 启动检查逻辑 initControls();
3. 手动获取计算后尺寸并更新画布
如果画布依赖CSS布局(比如百分比宽高),可以先获取计算后的样式尺寸,重新设置画布大小后再初始化控件:
document.body.appendChild(renderer.domElement); // 获取CSS计算后的宽高 const canvasStyle = window.getComputedStyle(renderer.domElement); const canvasWidth = parseInt(canvasStyle.width); const canvasHeight = parseInt(canvasStyle.height); // 重新设置画布尺寸 renderer.setSize(canvasWidth, canvasHeight); // 初始化控件 controls = new TrackballControls(camera, renderer.domElement);
内容的提问来源于stack exchange,提问作者theahura
相关产品推荐
相关产品推荐

