Skip to content

98. 实战:酷家乐装修编辑器(二)

Published:

这节开始进入酷家乐装修编辑器的开发。

首先我们写下布局:

image.png

可以分为 Header、Menu、Main、Properties 这四个组件。

创建项目:

npx create-vite home-decoration-editor

image.png

选择 react、typescript (前面一个编辑器用的 js,大的项目还是用 ts 写)

进入项目,安装依赖和 three.js:

npm install
npm install --save three
npm install --save-dev @types/three

安装 ant design 组件库:

npm install --save antd

改下 src/App.tsx

import './App.scss'
import Header from './components/Header';
import Menu from './components/Menu';
import Main from './components/Main';
import Properties from './components/Properties';

function App() {
  return <div className='wrap'>
    <Header />
    <div className='editor'>
      <Menu/>
      <Main/>
      <Properties/>
    </div>
  </div>
}

export default App

按照之前分析的结构,拆分 Header、Main、Menu、Properties 这四个组件:

image.png

放在 components 目录下。

安装下 sass

npm install --save-dev sass

改下 src/App.scss

body {
  margin: 0;
}

创建四个组件:

src/components/Header/index.tsx

function Header() {
    return <div className="Header">Header</div>
}

export default Header;

src/components/Main/index.tsx

function Main() {
    return <div className="Main">Main</div>
}

export default Main;

src/components/Menu/index.jsx

function Menu() {
    return <div className="Menu">Menu</div>
}

export default Menu;

src/components/Properties/index.jsx

function Properties() {
    return <div className="Properties">Properties</div>
}

export default Properties;

然后在 main.tsx 里去掉 index.css 和 StrictMode

image.png

跑一下:

npm run dev

image.png

image.png

然后来写下布局

image.png

.wrap {
  height: 100vh;
  display: flex;
  flex-direction: column;

  .Header {
    height: 60px;
    border-bottom: 1px solid #000;
  }

  .editor {
    flex: 1;
  }
}

竖直方向 flex 布局。

整体是 100vh,上面 60px 下面 flex 1

看下效果:

image.png

酷家乐下面部分的布局是这样的:

2025-05-19 11.03.59.gif

画布占据了整个网页宽度,在上面绝对定位放着两侧的面板。

我们也来写一下:

image.png

 .editor {
    flex: 1;

    position: relative;

    .Menu,.Properties {
      position: absolute;
      top: 0;
      width: 300px;
      height: calc(100vh - 60px);
      background: pink;
    }
    .Menu {
      left: 0;
      border-right: 1px solid #000;
    }
    .Properties {
      right: 0;
      background: orange;
      border-left: 1px solid #000;
    }
}

中间占据 100% 宽度,左右两侧是固定宽度绝对定位的两个面板。

2025-05-19 11.12.25.gif

这样,布局就完成了。

我们也可以加一下这个:

2025-05-19 11.13.42.gif

写个 div:

image.png

image.png

<div className="drawer-bar"></div>

写下样式:

image.png

.drawer-bar {
  width: 10px;
  height: 80px;
  background: black;
  position: absolute;
  right: -10px;
  top: 50%;
  transform: translateY(-50%);
  cursor:pointer;
}
.Properties {
  .drawer-bar {
    left: -10px;
  }
}

绝对定位,固定宽高。

看下效果:

image.png

点击的时候,改下 left、right

image.png

import { useState } from "react";

function Properties() {

    const [right, setRight] = useState(0);

    return <div className="Properties" style={{right: right}}>
        Properties
        <div className="drawer-bar" onClick={() => {
            setRight(right === 0 ? -300 : 0);
        }}></div>
    </div>
}

export default Properties;

用 state 保存 right,点击的时候修改 right 为 0 或 -300

2025-05-19 11.29.02.gif

给 left、right 加个过渡效果:

image.png

transition: left 0.5s ease-in-out,right 0.5s ease-in-out;

缓动的动画,0.5s

试一下:

2025-05-19 11.36.21.gif

平滑多了。

另一个组件也是同样,只不过改 left:

import { useState } from "react";

function Menu() {

    const [left, setLeft] = useState(0);

    return <div className="Menu" style={{left: left}}>
        Menu
        <div className="drawer-bar" onClick={() => {
            setLeft(left === 0 ? -300 : 0);
        }}></div>
    </div>
}

export default Menu;

2025-05-19 11.38.41.gif

这样,布局就完成了。

和酷家乐的一样:

2025-05-19 11.39.30.gif

案例代码上传了小册仓库

总结

这节我们实现了布局。

上面固定 60px,下面是 Main 占据整个宽度,左右两个面板绝对定位,固定宽度。

并且左右两边还可以点击按钮展开收起,通过修改 left、right,并且我们还加了一个过渡效果。

布局写完了,下节来写 threejs 部分。

评论