feat(editor): 将侧边栏激活面板状态同步至 uiService

This commit is contained in:
roymondchen 2026-06-11 15:12:56 +08:00
parent 4f284e8d9c
commit 6ba59c0d14
7 changed files with 65 additions and 7 deletions

View File

@ -201,7 +201,16 @@ export default defineConfig({
},
{
text: 'uiService',
link: '/api/editor/uiServiceMethods.md',
items: [
{
text: '方法',
link: '/api/editor/uiServiceMethods.md',
},
{
text: '事件',
link: '/api/editor/uiServiceEvents.md',
},
],
},
{
text: 'codeBlockService',

View File

@ -0,0 +1,28 @@
# uiService事件
## state-change
- **详情:** UI 状态发生变化时触发,[uiService.set()](./uiServiceMethods.md#set) 在写入的新值与旧值不同时触发
- **事件回调函数:** `(name: keyof UiState, value: UiState[typeof name], preValue: UiState[typeof name]) => void`
::: details 查看 UiState 类型定义
<<< @/../packages/editor/src/type.ts#UiState{ts}
:::
- **示例:**
```js
import { uiService } from '@tmagic/editor';
uiService.on('state-change', (name, value, preValue) => {
console.log(`${name} 从`, preValue, '变为', value);
});
uiService.set('zoom', 1.5);
```
:::tip
- 新值与旧值相同时不会触发该事件
- 通过 `set('stageRect', value)` 修改画布尺寸时,内部会走 `setStageRect` 逻辑并可能联动更新 `zoom`,但不会触发 `state-change` 事件
:::

View File

@ -13,7 +13,7 @@
- **详情:**
设置UI服务的状态
设置UI服务的状态。新值与旧值不同时会触发 [`state-change`](./uiServiceEvents.md#state-change) 事件
可用的状态键:
- `uiSelectMode`: UI选择模式
@ -31,6 +31,7 @@
- `showPageListButton`: 是否显示页面列表按钮
- `hideSlideBar`: 是否隐藏侧边栏
- `sideBarItems`: 侧边栏项目
- `sideBarActiveTabName`: 当前激活的侧边栏面板
- `navMenuRect`: 导航菜单尺寸
- `frameworkRect`: 框架尺寸

View File

@ -239,7 +239,12 @@ const unWatchEditorContentHeight = watch(
},
);
const activeTabName = ref(props.data?.status);
const activeTabName = computed<string>({
get: () => uiService.get('sideBarActiveTabName'),
set: (value) => uiService.set('sideBarActiveTabName', value),
});
uiService.set('sideBarActiveTabName', props.data?.status || '');
const getItemConfig = (data: SideItem): SideComponent => {
const map: Record<string, SideComponent> = {

View File

@ -62,6 +62,7 @@ const state = shallowReactive<UiState>({
showPageListButton: true,
hideSlideBar: false,
sideBarItems: [],
sideBarActiveTabName: '',
navMenuRect: {
left: 0,
top: 0,
@ -104,7 +105,13 @@ class Ui extends BaseService {
mask?.showRule(value as unknown as boolean);
}
const preValue = state[name];
state[name] = value;
if (preValue !== value) {
this.emit('state-change', name, value, preValue);
}
}
public get<K extends keyof UiState>(name: K) {

View File

@ -312,6 +312,8 @@ export interface UiState {
hideSlideBar: boolean;
/** 侧边栏面板配置 */
sideBarItems: SideComponent[];
/** 当前激活的侧边栏面板 */
sideBarActiveTabName: string;
// navMenu 的宽高
navMenuRect: {

View File

@ -4,15 +4,18 @@
* Copyright (C) 2025 Tencent.
*/
import { beforeEach, describe, expect, test, vi } from 'vitest';
import { defineComponent, h, nextTick } from 'vue';
import { defineComponent, h, nextTick, reactive } from 'vue';
import { mount } from '@vue/test-utils';
import Sidebar from '@editor/layouts/sidebar/Sidebar.vue';
const depService = { get: vi.fn(() => false) };
const uiState: Record<string, any> = reactive({});
const uiService = {
get: vi.fn(() => ({ left: 200 })),
set: vi.fn(),
get: vi.fn((name: string) => (name === 'sideBarActiveTabName' ? uiState.sideBarActiveTabName : { left: 200 })),
set: vi.fn((name: string, value: any) => {
uiState[name] = value;
}),
};
const propsService = {
getDisabledDataSource: vi.fn(() => false),
@ -91,7 +94,10 @@ beforeEach(() => {
vi.clearAllMocks();
propsService.getDisabledDataSource.mockReturnValue(false);
propsService.getDisabledCodeBlock.mockReturnValue(false);
uiService.get.mockReturnValue({ left: 200 });
Object.keys(uiState).forEach((key) => delete uiState[key]);
uiService.get.mockImplementation((name: string) =>
name === 'sideBarActiveTabName' ? uiState.sideBarActiveTabName : { left: 200 },
);
});
const baseProps = (extra: any = {}) => ({