Skip to content

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

Published:

这节我们把选中家具时的信息面板做一下:

2025-07-31 10.55.37.gif

去掉背景色:

image.png

然后用 antd 的表单来展示一下:

image.png

{
    curSelectedFurniture ? <div>
        <Form initialValues={
            curSelectedFurniture
        } style={{
            margin: 10
        }}>
            <Form.Item label="ID" name='id'>
                <Input disabled/>
            </Form.Item>
            <Form.Item label="位置 x" name={["position", 'x']}>
                <Input/>
            </Form.Item>
            <Form.Item label="位置 y" name={["position", 'y']}>
                <Input/>
            </Form.Item>
            <Form.Item label="位置 z" name={["position", 'z']}>
                <Input/>
            </Form.Item>
            <Form.Item label="角度 x" name={["rotation", 'x']}>
                <Input/>
            </Form.Item>
            <Form.Item label="角度 y" name={["rotation", 'y']}>
                <Input/>
            </Form.Item>
            <Form.Item label="角度 z" name={["rotation", 'z']}>
                <Input/>
            </Form.Item>
        </Form>
    </div> : null
}

2025-07-31 12.52.19.gif

信息展示出来了,但现在在表单里按删除键会把家具删除:

2025-07-31 12.52.42.gif

我们阻止下事件冒泡就好了:

image.png

onKeyDown={(evt) => {
    evt.stopPropagation();
}}

2025-07-31 12.55.12.gif

现在移动家具位置,切换选中的家具的时候,表单值都不会变化:

2025-07-31 12.55.45.gif

因为它只设置了初始值,我们要做下值的同步:

image.png

const [form] = useForm();
useEffect(() => {
    form.setFieldsValue(curSelectedFurniture);
}, [curSelectedFurniture]);
form={form}

用 useForm 拿到表单实例,切换选中的家具的时候,设置下表单值。

2025-07-31 12.59.18.gif

然后是编辑时同步表单值:

image.png

data 变化的时候也同步设置下就好了。

2025-07-31 13.02.39.gif

这个旋转角度显然用滑动输入条会更好。

image.png

范围是 -2π 到 2π

image.png

<Form.Item label="位置 x" name={["position", 'x']}>
    <InputNumber/>
</Form.Item>
<Form.Item label="位置 y" name={["position", 'y']}>
    <InputNumber disabled/>
</Form.Item>
<Form.Item label="位置 z" name={["position", 'z']}>
    <InputNumber/>
</Form.Item>
<Form.Item label="角度 x" name={["rotation", 'x']}>
    <Slider min={-Math.PI * 2} max={Math.PI * 2}/>
</Form.Item>
<Form.Item label="角度 y" name={["rotation", 'y']}>
    <Slider min={-Math.PI * 2} max={Math.PI * 2}/>
</Form.Item>
<Form.Item label="角度 z" name={["rotation", 'z']}>
    <Slider min={-Math.PI * 2} max={Math.PI * 2}/>
</Form.Item>

用 Slider 调整角度,位置应该是用 InputNumber,然后 y 方向禁用

2025-07-31 13.15.48.gif

然后编辑表单的时候同步到 store:

image.png

onValuesChange={handleValuesChange}
function handleValuesChange() {
    const values  = form.getFieldsValue();
    console.log(values);
}

表单变化的时候打印下表单值:

2025-07-31 13.19.35.gif

然后把它更到 store 里:

image.png

function handleValuesChange() {
    const values  = form.getFieldsValue();
    updateFurniture(values.id, 'position', values.position);
    updateFurniture(values.id, 'rotation', values.rotation);
}

试一下:

2025-07-31 13.23.17.gif

这样就能直接通过表单来修改家具位置角度了。

当然,这里角度也只支持绕 y 轴旋转:

2025-07-31 13.24.18.gif

把 x、z 方向的旋转禁用:

image.png

image.png

整体测试下:

2025-07-31 13.26.11.gif

这里还有个问题:

image.png

2D、3D 视图的家具旋转方向刚好相反。

这个也是因为我们之前 2D 视图整体旋转了 180 度的原因,家具的 rotation.y 也要旋转 180 度。

改 3 处地方:

image.png image.png

obj.rotation.y = furniture.rotation.y + Math.PI;

这样就好了:

image.png

顺便改下 title

image.png

image.png

这个墙的选中效果,我们暂时也用不到,去掉:

image.png

案例代码上传了小册仓库

总结

这节我们加上了家具信息编辑的表单。

选中家具的时候,用 antd 的 Form 来展示 position、rotation 等信息,角度用 Slider 滑动条。

data 变化的时候,同步修改表单的值。

表单值变化的时候,同步设置到 store。

这样,家具的信息编辑表单就完成了。

评论