Skip to content

124. 实战:酷家乐装修编辑器(二十八)

Published:

在酷家乐里,当你编辑完之后可以点击渲染进入全景浏览:

image.png

就会进入看效果的视角:

image.png

不再是编辑视角。

我们也来实现下这个全景浏览功能。

首先加一个渲染按钮:

image.png

<div className="btns">
    <Button type="primary"><CameraOutlined />渲染</Button>
</div>

加下样式:

image.png

display:flex;
justify-content: space-between;
.btns {
  margin-right: 20px;
  margin-top: 15px;
}

image.png

点击按钮的时候,要弹出一个单独的界面来预览:

image.png

我们写个新组件:

创建 src/components/Preview/index.tsx

import { CloseCircleOutlined } from "@ant-design/icons";

function Preview() {
    return <div id="preview">
        <div className='close-btn'>
            <CloseCircleOutlined />
        </div>
    </div>
}

export default Preview;

加一下样式:

image.png

#preview {
  position: absolute;
  background: pink;
  width: 100%;
  height: 100%;
  z-index: 10;

  .close-btn {
    position: absolute;
    right: 20px;
    top: 20px;
    font-size: 30px;
    cursor:pointer;
  }
}

引入下:

image.png

image.png

然后我们要在这里渲染一遍 3D 场景。

首先初始化一下:

image.png

useEffect(() => {
    const dom = document.getElementById('preview-container')!;
    const { } = initPreviewScene(dom);

    return () => {
      dom.innerHTML = '';
    }
}, []);
<div id="preview-container"></div>

加一个 dom,在这下面挂载 canvas

创建 Preview/init-preview.ts

import * as THREE from 'three';
import {
    OrbitControls
} from 'three/addons/controls/OrbitControls.js';

export function initPreviewScene(
    dom: HTMLElement
) {
    const scene = new THREE.Scene();

    const axesHelper = new THREE.AxesHelper(5000);
    scene.add(axesHelper);

    const directionalLight = new THREE.DirectionalLight(0xffffff);
    directionalLight.position.set(0, 1500, 0);
    scene.add(directionalLight);

    const ambientLight = new THREE.AmbientLight(0xffffff, 2.5);
    scene.add(ambientLight);

    const width = window.innerWidth;
    const height = window.innerHeight;

    const camera = new THREE.PerspectiveCamera(60, width / height, 1, 100000);
    camera.position.set(6000, 4000, 6000);
    camera.lookAt(0, 0, 0);

    const renderer = new THREE.WebGLRenderer({
        antialias: true
    });
    renderer.setSize(width, height);

    const controls = new OrbitControls(camera, renderer.domElement);

    function render() {
        renderer.render(scene, camera);
        requestAnimationFrame(render);
    }

    render();

    dom.append(renderer.domElement);

    window.onresize = function () {
        const width = window.innerWidth;
        const height = window.innerHeight;

        renderer.setSize(width,height);

        camera.aspect = width / height;
        camera.updateProjectionMatrix();
    };

    return {
        scene,
        camera,
        controls
    }
}

跑一下:

2025-07-28 21.23.09.gif

先不着急渲染这个场景,我们先把点击渲染按钮展示这个场景,以及点击关闭按钮关闭的逻辑写一下:

改下关闭按钮的颜色:

image.png

image.png

点预览按钮显示这个预览的场景:

image.png

点击关闭按钮隐藏。

明显需要跨组件通信,我们把它放到 store 里。

image.png

showPreview: boolean
toggleShowPreview(): void;
showPreview: false,
toggleShowPreview() {
    set(state => {
        return {
            ...state,
            showPreview: !state.showPreview
        }
    })
},

加一个 showPreview 的布尔值和修改它的方法。

然后我们用这个来控制预览界面的显示隐藏:

image.png

const { showPreview, toggleShowPreview } = useHouseStore();
style={{display: showPreview ? 'block' :  'none'}}
onClick={toggleShowPreview}

点击关闭的时候切换显示隐藏。

点击渲染按钮的时候也是:

image.png

const { toggleShowPreview } = useHouseStore();
onClick={() => toggleShowPreview()}

试下效果:

2025-07-28 22.21.46.gif

这样,预览场景的初始化就完成了。

案例代码上传了小册仓库

总结

这节我们加了一下预览场景,它是用来看编辑后的效果的。

我们单独加了一个 Preview 组件和对应的场景初始化代码,点击渲染按钮的时候展示这个场景,点击关闭按钮隐藏。

下节我们来实现预览场景里的内容。

评论