我正在使用react和three.js在浏览器中显示一些3D模型。只要three.js组件是页面上唯一具有可见内容的元素,一切都可以正常工作。 three.js画布将调整大小,就好了。您可以将其包装在其他容器中,但仍然可以正常工作。当另一个元素或组件作为同级添加时,问题就开始了。
我想有一个带有固定宽度边栏的视口。我使用的是flexbox行容器,该容器包装在侧边栏组件(设置了最小宽度的简单div)和响应性three.js组件中。
将窗口的大小调整得更大可以很好地工作,画布会适当地填充浏览器窗口。但是,当将窗口调整为较小的尺寸时,画布无法根据静态宽度侧栏剩余的可用空间正确地重新计算其大小,从而导致画布无法完全适合浏览器并引入滚动条。
画布确实会缩小一些,但不足以使其完全保留在浏览器窗口中。如果某个组件位于three.js组件之上或之下,则在垂直方向上会出现相同的问题。如果在浏览器窗口较小的情况下重新编译应用程序,则刷新后的视图将适当调整画布的大小。
按照StackOverflow上许多答案的建议,Three.js反应代码看起来像这样:
export class Viewport extends React.Component {
componentDidMount() {
const width = this.mount.clientWidth;
const height = this.mount.clientHeight;
window.addEventListener("resize", this.handleWindowResize);
// setup scene
this.scene = new THREE.Scene();
//setup camera
this.camera = new THREE.PerspectiveCamera( 75, width / height, 0.1, 1000 );
this.camera.position.set( 0, 5, 10 );
// setup rendering
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setClearColor('#666666');
this.renderer.setSize(width, height, false);
this.mount.appendChild(this.renderer.domElement);
// setup geo
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: '#433F81' });
this.cube = new THREE.Mesh(geometry, material);
this.scene.add(this.cube);
...
}
componentWillUnmount() {
window.removeEventListener("resize", this.handleWindowResize);
this.mount.removeChild(this.renderer.domElement);
}
handleWindowResize = () => {
const width = this.mount.clientWidth;
const height = this.mount.clientHeight;
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix();
this.renderer.setSize(width, height, false);
};
render() {
return (
<div className="viewport" style={{display: 'flex', width: "100%", height: "100%"}} ref={(mount) => { this.mount = mount }} />
);
}
}
样式是简单的CSS Flexbox,将元素设置为全宽和全高(100%),并且边栏具有设置的最小宽度。
.flex-row-container {
display: flex;
flex-flow: row;
height: 100%;
width: 100%;
}
.sidebar {
display: block;
min-width: 250px;
background-color: var(--color-mid-gray);
margin: 3px 4px 3px 4px;
box-sizing: border-box;
border: 1px solid var(--color-mid-gray);
outline: 3px solid var(--color-mid-gray);
}
我想念什么?
使用element.clientWidth
可能会得到不正确的值。您是否尝试过使用element.getBoundingClientRect()
代替?
element.getBoundingClientRect()
所以评论后,我想我可以按照您的意愿来做。
基本上,我删除了视口上的const rect = this.mount.getBoundingClientRect();
const width = rect.width;
const height = rect.height;
设置,因为它是display:flex
元素的子元素(flex-row-container div),它不需要它,但需要display:flex
来设置它的显示方式在flexbox内(我在CSS而不是JSX中做了)。然后,问题就变成了视口div将扩展,但不会收缩(因为它包含画布),因此添加flex:1 1 auto
可以解决此问题。进行了这些更改之后,overflow:hidden
将获得所需的结果,然后可以将其用于设置三个画布大小。
请参见this.mount.clientWidth
。我在示例中添加了渲染和动画,因此可以轻松看到结果。
希望这会有所帮助。