上节把家具的平移、旋转等编辑功能实现了:

这节我们把编辑后的 position、rotation 存入 store 中,并且在 2d 视图中把它画出来。
因为后面可能添加多个,我们给每个家具一个唯一的 id:


渲染家具的时候设置 name:

gltf.scene.name = furniture.id
这样更新的时候就可以根据 id 查找了。
添加一个更新家具的方法:

export interface Action {
setData(data: State['data']): void;
updateFurniture(id: string, type: 'position' | 'rotation', info: Vector3): void;
}
updateFurniture(id, type, info) {
set(state => {
return {
...state,
data: {
...state.data,
furnitures: state.data.furnitures.map(item => {
if(item.id === id) {
if(type === 'position') {
item.position.x = info.x;
item.position.y = info.y;
item.position.z = info.z;
} else {
item.rotation.x = info.x;
item.rotation.y = info.y;
item.rotation.z = info.z;
}
}
return item;
})
}
}
})
}
然后改变位置、旋转角度的时候更新下 store:


把这个更新方法传入 init3D
updateFurniture: Action['updateFurniture']
change 的时候调用下来更新 store:

光这样还不行,现在有个严重的问题。
因为 data 一变,就会删除整个场景:

我们得区分这是改变家具而不是清空数据:

加个判断就好了
if(data.walls.length) {
return;
}
同样,渲染 house 的时候也要判断,如果已经有了,那就是更新家具:

const houseObj = scene.getObjectByName('house')!;
if(houseObj) {
data.furnitures.forEach(furniture => {
const obj = houseObj.getObjectByName(furniture.id);
if(obj) {
obj.position.set(
furniture.position.x,
furniture.position.y,
furniture.position.z
);
obj.rotation.x = furniture.rotation.x;
obj.rotation.y = furniture.rotation.y;
obj.rotation.z = furniture.rotation.z;
}
})
return;
}
为了观察 json 是不是变了,我们把它渲染出来:

const { data } = useHouseStore();
<pre>
{JSON.stringify(data.furnitures, null, 4)}
</pre>
试一下:

平移和旋转家具的时候,可以看到 store 里的数据确实改变了。
这样,编辑家具到保存到 json 里就都完成了。
但现在编辑的数据刷新就没了:

我们加一下 store 的持久化:


const stateCreator: StateCreator<State & Action> = (set, get) => {
};
const useHouseStore = create<State & Action>()(persist(stateCreator, {
name: 'house'
}));
试下效果:

现在编辑完刷新页面依然保存着编辑后的结果。
在 localStorage 里也能看到保存的数据:

这样,数据持久化就完成了。
案例代码上传了小册仓库
总结
这节我们做了编辑结果保存到 store 的功能。
我们在 store 添加了一个更新家具信息的方法,给家具一个 id。
改变家具位置、角度的时候调用这个方法来更新 json 里的家具信息。
要注意的是之前清空数据、渲染房屋都是监听 data 的变化,改了家具也会改 data,会不断触发清空数据,所以我们要处理下,判断出这种情况。
家具编辑的结果保存好后,下节我们把家具同步渲染到 2D 视图。