保存
This commit is contained in:
262
.qoder/repowiki/zh/content/事件系统/事件系统.md
Normal file
262
.qoder/repowiki/zh/content/事件系统/事件系统.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# 事件系统
|
||||
|
||||
<cite>
|
||||
**Referenced Files in This Document **
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts)
|
||||
- [IEventBuilder.ts](file://src/events/IEventBuilder.ts)
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts)
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [核心组件分析](#核心组件分析)
|
||||
3. [接口契约规范](#接口契约规范)
|
||||
4. [事件管理器扩展实现](#事件管理器扩展实现)
|
||||
5. [跨组件通信实例](#跨组件通信实例)
|
||||
6. [错误处理与内存泄漏防范](#错误处理与内存泄漏防范)
|
||||
|
||||
## 简介
|
||||
本文档全面记录了自定义事件总线系统的实现原理与使用方法。基于 `EventBuilderImpl` 类,详细解释 `addEventListener`、`removeEventListener` 和 `notifyEvent` 三个核心方法的工作机制,包括 `once`、`immediate` 等选项的行为特征。文档描述了 `IEventBuilder` 接口的契约规范,并分析了 `DesktopEventManager` 和 `WindowFormEventManager` 如何继承和扩展基础事件功能。同时提供跨组件通信的实际用例,并说明错误处理和内存泄漏防范措施。
|
||||
|
||||
## 核心组件分析
|
||||
|
||||
### EventBuilderImpl 实现机制
|
||||
|
||||
`EventBuilderImpl` 是事件总线系统的核心实现类,采用泛型设计支持类型安全的事件管理。其内部通过 `Map<keyof Events, Set<HandlerWrapper<Events[keyof Events]>>>` 结构存储事件处理器,确保高效的事件查找与去重。
|
||||
|
||||
#### addEventListener 方法工作机制
|
||||
该方法用于注册事件监听器,具有以下特性:
|
||||
- **去重机制**:在添加前检查是否已存在相同处理器函数,避免重复绑定
|
||||
- **即时执行**:当 `options.immediate` 为 `true` 时,立即同步执行一次处理器
|
||||
- **单次监听**:通过 `options.once` 标记,使监听器在触发后自动移除
|
||||
- **类型安全**:利用 TypeScript 泛型约束确保事件名与处理器参数类型匹配
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> ValidateHandler["验证处理器非空"]
|
||||
ValidateHandler --> HasEvent{"是否存在事件队列?"}
|
||||
HasEvent --> |否| CreateSet["创建新的处理器集合"]
|
||||
CreateSet --> AddToSet
|
||||
HasEvent --> |是| GetSet["获取现有集合"]
|
||||
GetSet --> AddToSet
|
||||
AddToSet --> CheckDuplicate{"是否已存在?"}
|
||||
CheckDuplicate --> |否| AddWrapper["添加包装器(once标记)"]
|
||||
AddWrapper --> CheckImmediate{"是否立即执行?"}
|
||||
CheckImmediate --> |是| ExecuteNow["立即执行处理器"]
|
||||
CheckImmediate --> |否| End([结束])
|
||||
ExecuteNow --> End
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L20-L46)
|
||||
|
||||
#### removeEventListener 方法工作机制
|
||||
该方法通过遍历对应事件的处理器集合,精确匹配并删除指定的处理器函数引用,实现精准解绑。
|
||||
|
||||
#### notifyEvent 方法工作机制
|
||||
通知方法按顺序调用所有注册的处理器,并处理以下特殊情况:
|
||||
- 自动清理标记为 `once` 的监听器
|
||||
- 捕获并记录处理器执行中的异常,防止中断其他监听器
|
||||
- 支持任意数量的参数传递
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Publisher as "发布者"
|
||||
participant EventBus as "EventBus"
|
||||
participant Handler1 as "处理器1"
|
||||
participant Handler2 as "处理器2"
|
||||
Publisher->>EventBus : notifyEvent('event', args)
|
||||
EventBus->>EventBus : 获取处理器集合
|
||||
loop 每个处理器
|
||||
EventBus->>Handler1 : 执行处理器
|
||||
Handler1-->>EventBus : 完成
|
||||
EventBus->>EventBus : 检查once标记
|
||||
alt 是单次监听
|
||||
EventBus->>EventBus : 从集合中移除
|
||||
end
|
||||
EventBus->>Handler2 : 执行处理器
|
||||
Handler2-->>EventBus : 完成
|
||||
end
|
||||
EventBus-->>Publisher : 通知完成
|
||||
Note over Handler1,Handler2 : 异常被捕获,不影响其他处理器执行
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L75-L90)
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
|
||||
## 接口契约规范
|
||||
|
||||
### IEventBuilder 接口定义
|
||||
`IEventBuilder` 接口定义了事件管理器的标准行为契约,继承自 `IDestroyable` 接口以支持资源清理。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class IEventBuilder {
|
||||
<<interface>>
|
||||
+addEventListener(eventName, handler, options) : void
|
||||
+removeEventListener(eventName, handler) : void
|
||||
+notifyEvent(eventName, ...args) : void
|
||||
}
|
||||
class IDestroyable {
|
||||
<<interface>>
|
||||
+destroy() : void
|
||||
}
|
||||
IEventBuilder --|> IDestroyable : 继承
|
||||
class EventBuilderImpl {
|
||||
-_eventHandlers : Map<string, Set<HandlerWrapper>>
|
||||
+addEventListener()
|
||||
+removeEventListener()
|
||||
+notifyEvent()
|
||||
+destroy()
|
||||
}
|
||||
EventBuilderImpl ..|> IEventBuilder : 实现
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [IEventBuilder.ts](file://src/events/IEventBuilder.ts#L13-L46)
|
||||
|
||||
接口方法参数说明:
|
||||
|
||||
| 方法 | 参数 | 类型 | 描述 |
|
||||
|------|------|------|------|
|
||||
| addEventListener | eventName | keyof Events | 事件名称 |
|
||||
| | handler | F extends Events[E] | 事件处理器函数 |
|
||||
| | options | {immediate?: boolean, immediateArgs?: Parameters<F>, once?: boolean} | 配置选项 |
|
||||
| removeEventListener | eventName | keyof Events | 事件名称 |
|
||||
| | handler | F extends Events[E] | 要移除的处理器函数 |
|
||||
| notifyEvent | eventName | keyof Events | 事件名称 |
|
||||
| | ...args | Parameters<F> | 传递给处理器的参数 |
|
||||
|
||||
**Section sources**
|
||||
- [IEventBuilder.ts](file://src/events/IEventBuilder.ts#L1-L46)
|
||||
|
||||
## 事件管理器扩展实现
|
||||
|
||||
### DesktopEventManager 桌面事件管理
|
||||
`DesktopEventManager` 通过实例化 `EventBuilderImpl<IDesktopEvent>` 创建专用的桌面事件总线,定义了桌面应用相关的特定事件类型。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class IDesktopEvent {
|
||||
<<interface>>
|
||||
+desktopAppPosChange(info : IDesktopAppIcon) : void
|
||||
}
|
||||
class desktopEM {
|
||||
+instance of EventBuilderImpl<IDesktopEvent>
|
||||
}
|
||||
desktopEM ..> IDesktopEvent : 类型约束
|
||||
desktopEM ..> EventBuilderImpl : 实例化
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L1-L16)
|
||||
|
||||
### WindowFormEventManager 窗口表单事件管理
|
||||
`WindowFormEventManager` 提供了窗口生命周期管理的完整事件体系,涵盖最小化、最大化、关闭、聚焦等状态变化。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class IWindowFormEvent {
|
||||
<<interface>>
|
||||
+windowFormMinimize(id : string) : void
|
||||
+windowFormMaximize(id : string) : void
|
||||
+windowFormRestore(id : string) : void
|
||||
+windowFormClose(id : string) : void
|
||||
+windowFormFocus(id : string) : void
|
||||
+windowFormDataUpdate(data : IWindowFormDataUpdateParams) : void
|
||||
+windowFormCreated() : void
|
||||
}
|
||||
class wfem {
|
||||
+instance of EventBuilderImpl<IWindowFormEvent>
|
||||
}
|
||||
class IWindowFormDataUpdateParams {
|
||||
+id : string
|
||||
+state : TWindowFormState
|
||||
+width : number
|
||||
+height : number
|
||||
+x : number
|
||||
+y : number
|
||||
}
|
||||
wfem ..> IWindowFormEvent : 类型约束
|
||||
IWindowFormEvent ..> IWindowFormDataUpdateParams : 引用
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L1-L61)
|
||||
|
||||
**Section sources**
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L1-L16)
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L1-L61)
|
||||
|
||||
## 跨组件通信实例
|
||||
|
||||
### 桌面应用位置更新场景
|
||||
```typescript
|
||||
// 发布者组件
|
||||
const updatePosition = (iconInfo) => {
|
||||
desktopEM.notifyEvent('desktopAppPosChange', iconInfo)
|
||||
}
|
||||
|
||||
// 订阅者组件
|
||||
desktopEM.addEventListener('desktopAppPosChange', (info) => {
|
||||
console.log('应用位置更新:', info.name, info.x, info.y)
|
||||
}, {
|
||||
immediate: true,
|
||||
immediateArgs: [currentIconInfo]
|
||||
})
|
||||
```
|
||||
|
||||
### 窗口状态变更场景
|
||||
```typescript
|
||||
// 窗口最小化
|
||||
wfem.notifyEvent('windowFormMinimize', 'win123')
|
||||
|
||||
// 监听窗口最小化(仅一次)
|
||||
wfem.addEventListener('windowFormMinimize', (id) => {
|
||||
addToTaskbar(id)
|
||||
}, {
|
||||
once: true
|
||||
})
|
||||
|
||||
// 监听所有窗口数据更新
|
||||
wfem.addEventListener('windowFormDataUpdate', (data) => {
|
||||
saveWindowState(data)
|
||||
})
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L1-L16)
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L1-L61)
|
||||
|
||||
## 错误处理与内存泄漏防范
|
||||
|
||||
### 错误处理机制
|
||||
系统在关键执行路径上均包含异常捕获:
|
||||
- 处理器执行时捕获异常,防止中断其他监听器
|
||||
- 控制台输出错误信息便于调试
|
||||
- 不抛出异常保证事件总线稳定性
|
||||
|
||||
### 内存泄漏防范措施
|
||||
1. **及时解绑**:使用 `removeEventListener` 移除不再需要的监听器
|
||||
2. **单次监听**:对只需执行一次的逻辑使用 `once: true` 选项
|
||||
3. **资源清理**:实现 `destroy()` 方法清空所有事件处理器
|
||||
4. **实例管理**:通过单例模式管理事件总线实例生命周期
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[组件挂载] --> B[添加事件监听]
|
||||
B --> C[设置once或immediate]
|
||||
C --> D[组件运行]
|
||||
D --> E{组件卸载?}
|
||||
E --> |是| F[调用removeEventListener]
|
||||
F --> G[或调用destroy清理所有]
|
||||
G --> H[防止内存泄漏]
|
||||
E --> |否| D
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L92-L94)
|
||||
207
.qoder/repowiki/zh/content/事件系统/核心事件总线.md
Normal file
207
.qoder/repowiki/zh/content/事件系统/核心事件总线.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# 核心事件总线
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts)
|
||||
- [IEventBuilder.ts](file://src/events/IEventBuilder.ts)
|
||||
- [IDestroyable.ts](file://src/common/types/IDestroyable.ts)
|
||||
- [EventManager.ts](file://src/events/EventManager.ts)
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts)
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [核心数据结构设计](#核心数据结构设计)
|
||||
3. [泛型类型安全机制](#泛型类型安全机制)
|
||||
4. [事件监听器管理](#事件监听器管理)
|
||||
- [addEventListener 方法详解](#addeventlistener-方法详解)
|
||||
- [removeEventListener 方法详解](#removeeventlistener-方法详解)
|
||||
5. [事件通知与分发](#事件通知与分发)
|
||||
6. [资源清理与内存泄漏防范](#资源清理与内存泄漏防范)
|
||||
7. [实际应用示例](#实际应用示例)
|
||||
8. [总结](#总结)
|
||||
|
||||
## 简介
|
||||
|
||||
`EventBuilderImpl` 类是本系统事件机制的核心实现,提供了一个类型安全、功能完整的事件总线系统。该类实现了 `IEventBuilder` 接口,遵循发布-订阅模式,支持事件的注册、移除和触发,并具备立即执行、一次性监听等高级特性。通过继承 `IDestroyable` 接口,它还提供了资源清理能力,有效防止内存泄漏。
|
||||
|
||||
该事件系统被多个模块广泛使用,包括全局事件管理器(`eventManager`)、桌面事件管理器(`desktopEM`)和窗口表单事件管理器(`wfem`),构成了整个应用的通信骨架。
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
- [IEventBuilder.ts](file://src/events/IEventBuilder.ts#L13-L46)
|
||||
- [IDestroyable.ts](file://src/common/types/IDestroyable.ts#L4-L7)
|
||||
|
||||
## 核心数据结构设计
|
||||
|
||||
`EventBuilderImpl` 采用 `Map` 和 `Set` 的组合来高效管理事件监听器,这种设计在性能和内存使用上达到了良好的平衡。
|
||||
|
||||
其核心是一个私有成员 `_eventHandlers`,其类型为 `Map<keyof Events, Set<HandlerWrapper<Events[keyof Events]>>>`。这个数据结构的含义是:
|
||||
- **外层 Map**:以事件名称(`keyof Events`)作为键,确保每个事件名对应一个独立的监听器集合。
|
||||
- **内层 Set**:存储特定事件的所有监听器包装对象(`HandlerWrapper`)。使用 `Set` 而非数组可以天然避免重复添加同一个监听函数,并且插入和删除操作的时间复杂度为 O(1)。
|
||||
|
||||
`HandlerWrapper` 是一个简单的接口,包含两个属性:`fn`(原始的监听函数)和 `once`(布尔值,标记是否为一次性监听器)。这种包装方式将业务逻辑(函数本身)与元数据(如 `once` 标志)分离,使得事件管理更加灵活。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class EventBuilderImpl~Events~ {
|
||||
-_eventHandlers : Map~keyof Events, Set~HandlerWrapper~Events[keyof Events]~~~
|
||||
+addEventListener()
|
||||
+removeEventListener()
|
||||
+notifyEvent()
|
||||
+destroy()
|
||||
}
|
||||
class HandlerWrapper~T~ {
|
||||
+fn : T
|
||||
+once : boolean
|
||||
}
|
||||
EventBuilderImpl --> "0..*" HandlerWrapper : 包含
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L15)
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L15)
|
||||
|
||||
## 泛型类型安全机制
|
||||
|
||||
`EventBuilderImpl` 类通过 TypeScript 的泛型系统实现了严格的类型安全。其定义为 `class EventBuilderImpl<Events extends IEventMap>`,其中 `Events` 是一个必须符合 `IEventMap` 接口约束的泛型类型。
|
||||
|
||||
`IEventMap` 接口定义了事件映射的基本结构:一个索引签名 `[key: string]: (...args: any[]) => void`,表示键是字符串类型的事件名,值是任意参数的无返回值函数。
|
||||
|
||||
当实例化 `EventBuilderImpl` 时,需要传入一个具体的事件接口。例如,在 `WindowFormEventManager.ts` 中定义了 `IWindowFormEvent` 接口,并将其作为泛型参数:
|
||||
|
||||
```typescript
|
||||
export const wfem = new EventBuilderImpl<IWindowFormEvent>()
|
||||
```
|
||||
|
||||
这种设计带来了以下优势:
|
||||
1. **编译时检查**:在调用 `addEventListener` 或 `notifyEvent` 时,TypeScript 编译器会根据 `IWindowFormEvent` 的定义检查事件名和参数类型是否正确。
|
||||
2. **智能提示**:开发者在编写代码时能获得准确的事件名和参数类型提示。
|
||||
3. **防止错误**:无法订阅未在接口中定义的事件,也无法传递错误类型的参数。
|
||||
|
||||
**Section sources**
|
||||
- [IEventBuilder.ts](file://src/events/IEventBuilder.ts#L4-L7)
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L5-L59)
|
||||
|
||||
## 事件监听器管理
|
||||
|
||||
### addEventListener 方法详解
|
||||
|
||||
`addEventListener` 方法用于向事件总线注册新的监听器。它接收三个参数:事件名、处理函数和可选的配置项。
|
||||
|
||||
#### 配置项行为逻辑
|
||||
- **immediate (立即执行)**:如果设置为 `true`,则在添加监听器后立即同步执行一次该函数。
|
||||
- **immediateArgs (立即执行参数)**:为 `immediate` 执行阶段提供参数。若未指定,则使用空数组。
|
||||
- **once (一次性监听)**:如果设置为 `true`,则该监听器在第一次被触发后自动从事件队列中移除。
|
||||
|
||||
#### 实现细节
|
||||
1. **空值检查**:首先检查 `handler` 是否存在,避免无效监听器。
|
||||
2. **惰性初始化**:如果这是该事件的第一个监听器,则创建一个新的 `Set` 来存放后续的 `HandlerWrapper`。
|
||||
3. **去重机制**:在添加前,通过遍历 `Set` 并比较 `wrapper.fn === handler` 来确保不会重复添加相同的函数引用。
|
||||
4. **异常捕获**:在执行 `immediate` 回调时,使用 `try-catch` 捕获任何可能抛出的异常,并将其输出到控制台,防止因单个监听器的错误而中断主流程。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> CheckHandler["检查 handler 是否为空"]
|
||||
CheckHandler --> |否| InitSet["检查事件对应的 Set 是否存在"]
|
||||
InitSet --> |否| CreateSet["创建新的 Set"]
|
||||
CreateSet --> GetSet["获取事件对应的 Set"]
|
||||
InitSet --> |是| GetSet
|
||||
GetSet --> CheckDuplicate["检查是否已存在相同 handler"]
|
||||
CheckDuplicate --> |否| AddWrapper["添加 HandlerWrapper 到 Set"]
|
||||
AddWrapper --> CheckImmediate["检查 immediate 选项"]
|
||||
CheckImmediate --> |是| ExecuteNow["立即执行 handler"]
|
||||
ExecuteNow --> End([结束])
|
||||
CheckImmediate --> |否| End
|
||||
CheckHandler --> |是| End
|
||||
CheckDuplicate --> |是| End
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L20-L46)
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L20-L46)
|
||||
|
||||
### removeEventListener 方法详解
|
||||
|
||||
`removeEventListener` 方法负责从事件队列中移除指定的监听器。
|
||||
|
||||
其实现的关键在于**引用比对去重机制**。由于监听器是以 `HandlerWrapper` 对象的形式存储在 `Set` 中的,直接比较 `Set` 中的对象与传入的 `handler` 函数是不相等的。因此,该方法会遍历 `Set` 中的每一个 `wrapper`,并使用 `wrapper.fn === handler` 来精确匹配原始的函数引用。
|
||||
|
||||
一旦找到匹配项,就调用 `set.delete(wrapper)` 将其从 `Set` 中移除。这种基于引用的比对确保了只有完全相同的函数实例才会被移除,保证了操作的准确性。
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L55-L64)
|
||||
|
||||
## 事件通知与分发
|
||||
|
||||
`notifyEvent` 方法是事件系统的触发点,负责通知所有订阅了特定事件的监听器。
|
||||
|
||||
其工作流程如下:
|
||||
1. **存在性检查**:首先检查是否存在该事件名对应的监听器集合,若不存在则直接返回。
|
||||
2. **批量通知**:遍历该事件名对应 `Set` 中的所有 `HandlerWrapper`。
|
||||
3. **异常捕获**:在调用每个监听器的 `fn(...args)` 时,使用 `try-catch` 块包裹,确保单个监听器的错误不会影响其他监听器的执行。
|
||||
4. **once 监听器清理**:在成功调用一个监听器后,检查其 `once` 标志。如果为 `true`,则立即将其从 `Set` 中删除,实现一次性监听的功能。
|
||||
|
||||
这种“先通知,后清理”的策略保证了即使在 `once` 监听器执行过程中有其他代码尝试移除它,也不会产生竞态条件。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Publisher as 事件发布者
|
||||
participant EventBus as EventBuilderImpl
|
||||
participant ListenerA as 监听器 A (once : true)
|
||||
participant ListenerB as 监听器 B (once : false)
|
||||
Publisher->>EventBus : notifyEvent('click', x, y)
|
||||
EventBus->>ListenerA : 执行 fn(x, y)
|
||||
ListenerA-->>EventBus : 完成
|
||||
EventBus->>EventBus : 检查 wrapper.once == true
|
||||
EventBus->>EventBus : 从 Set 中删除 ListenerA
|
||||
EventBus->>ListenerB : 执行 fn(x, y)
|
||||
ListenerB-->>EventBus : 完成
|
||||
EventBus-->>Publisher : 通知完成
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L75-L90)
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L75-L90)
|
||||
|
||||
## 资源清理与内存泄漏防范
|
||||
|
||||
`EventBuilderImpl` 通过多种策略有效防范内存泄漏:
|
||||
|
||||
1. **显式销毁接口**:通过实现 `IDestroyable` 接口,提供了 `destroy()` 方法。调用此方法会清空 `_eventHandlers` Map,释放所有对监听器函数的引用,使它们可以被垃圾回收器回收。这对于长生命周期的应用或动态创建/销毁的组件至关重要。
|
||||
|
||||
2. **监听器去重**:`addEventListener` 方法中的去重逻辑防止了同一函数被多次添加,避免了不必要的内存占用和重复执行。
|
||||
|
||||
3. **once 监听器自动清理**:`once` 选项确保了一次性监听器在执行后立即被移除,无需手动清理。
|
||||
|
||||
4. **异常隔离**:`try-catch` 机制保证了事件分发过程的健壮性,防止因监听器内部错误导致整个事件系统崩溃。
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L92-L94)
|
||||
- [IDestroyable.ts](file://src/common/types/IDestroyable.ts#L4-L7)
|
||||
|
||||
## 实际应用示例
|
||||
|
||||
以下是 `EventBuilderImpl` 在项目中的具体应用实例:
|
||||
|
||||
- **全局事件管理器**:在 `EventManager.ts` 中,`eventManager` 实例被用来管理认证状态改变 (`onAuthChange`) 和主题切换 (`onThemeChange`) 等全局事件。
|
||||
- **桌面事件管理器**:在 `DesktopEventManager.ts` 中,`desktopEM` 实例用于响应桌面应用图标位置的变化 (`desktopAppPosChange`)。
|
||||
- **窗口表单事件管理器**:在 `WindowFormEventManager.ts` 中,`wfem` 实例监控窗口的最小化、最大化、关闭等生命周期事件。
|
||||
|
||||
这些预定义的事件管理器实例化了 `EventBuilderImpl`,并通过具体的事件接口(如 `IWindowFormEvent`)锁定了可用的事件集,为不同模块提供了清晰、类型安全的通信契约。
|
||||
|
||||
**Section sources**
|
||||
- [EventManager.ts](file://src/events/EventManager.ts#L3-L34)
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L3-L15)
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L3-L60)
|
||||
|
||||
## 总结
|
||||
|
||||
`EventBuilderImpl` 作为一个轻量级但功能完备的事件总线实现,通过精心设计的数据结构(`Map`+`Set`)和 TypeScript 泛型,实现了高性能、类型安全的事件管理。其 `addEventListener`、`removeEventListener` 和 `notifyEvent` 方法构成了一个健壮的发布-订阅循环,而 `immediate`、`once` 等选项以及异常捕获机制则增强了其实用性和可靠性。最后,通过 `IDestroyable` 接口提供的 `destroy` 方法,确保了资源的可管理性,有效防止了内存泄漏,是构建可维护前端应用的理想选择。
|
||||
187
.qoder/repowiki/zh/content/事件系统/桌面事件管理器.md
Normal file
187
.qoder/repowiki/zh/content/事件系统/桌面事件管理器.md
Normal file
@@ -0,0 +1,187 @@
|
||||
<cite>
|
||||
**本文档中引用的文件**
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts)
|
||||
- [IDesktopAppIcon.ts](file://src/ui/types/IDesktopAppIcon.ts)
|
||||
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [引言](#引言)
|
||||
2. [核心事件总线架构](#核心事件总线架构)
|
||||
3. [桌面事件接口定义](#桌面事件接口定义)
|
||||
4. [事件管理器实例化与类型注入](#事件管理器实例化与类型注入)
|
||||
5. [应用图标位置变化事件语义解析](#应用图标位置变化事件语义解析)
|
||||
6. [桌面容器中的事件监听实践](#桌面容器中的事件监听实践)
|
||||
7. [拖拽结束时的事件发布机制](#拖拽结束时的事件发布机制)
|
||||
8. [总结](#总结)
|
||||
|
||||
## 引言
|
||||
|
||||
本文档详细阐述了`DesktopEventManager`如何基于核心事件总线构建特定领域的事件系统。通过分析`IDesktopEvent`接口、`desktopEM`实例化过程以及在`useDesktopContainerInit`中的实际用例,全面揭示该事件管理器的设计原理与运行机制。
|
||||
|
||||
## 核心事件总线架构
|
||||
|
||||
`DesktopEventManager`并非独立实现事件机制,而是基于一个通用的核心事件总线——`EventBuilderImpl`类进行领域特化。这种设计模式实现了关注点分离:底层提供统一的事件订阅与通知能力,上层定义具体业务语义。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class IEventBuilder~Events~ {
|
||||
<<interface>>
|
||||
+addEventListener(eventName, handler, options)
|
||||
+removeEventListener(eventName, handler)
|
||||
+notifyEvent(eventName, ...args)
|
||||
}
|
||||
class EventBuilderImpl~Events~ {
|
||||
-_eventHandlers : Map<keyof Events, Set<HandlerWrapper>>
|
||||
+addEventListener()
|
||||
+removeEventListener()
|
||||
+notifyEvent()
|
||||
+destroy()
|
||||
}
|
||||
class IDesktopEvent {
|
||||
<<interface>>
|
||||
+desktopAppPosChange(info : IDesktopAppIcon)
|
||||
}
|
||||
class DesktopEventManager {
|
||||
+desktopEM : EventBuilderImpl<IDesktopEvent>
|
||||
}
|
||||
EventBuilderImpl --> IEventBuilder : "implements"
|
||||
DesktopEventManager ..> IDesktopEvent : "defines"
|
||||
DesktopEventManager ..> EventBuilderImpl : "instantiates"
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L7-L15)
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L7-L15)
|
||||
|
||||
## 桌面事件接口定义
|
||||
|
||||
`IDesktopEvent`接口继承自泛型事件映射接口`IEventMap`,专门用于声明桌面环境下的各类事件。其核心成员是`desktopAppPosChange`事件,明确表达了“桌面应用位置改变”的业务语义。
|
||||
|
||||
该接口采用TypeScript的索引签名与函数类型组合方式,为每个事件名称绑定对应的回调函数签名,确保类型安全。
|
||||
|
||||
**Section sources**
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L7-L12)
|
||||
|
||||
## 事件管理器实例化与类型注入
|
||||
|
||||
`desktopEM`是一个全局单例实例,通过`new EventBuilderImpl<IDesktopEvent>()`创建。此处的关键在于泛型参数`IDesktopEvent`的注入,它将通用的`EventBuilderImpl`约束为仅支持处理`IDesktopEvent`所定义的事件类型。
|
||||
|
||||
这种类型注入机制保证了:
|
||||
- 订阅时只能监听`desktopAppPosChange`等预定义事件
|
||||
- 发布时必须提供符合`IDesktopAppIcon`结构的数据
|
||||
- 编译期即可捕获类型错误,提升代码健壮性
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Code as "源码"
|
||||
participant Compiler as "TypeScript编译器"
|
||||
participant Runtime as "运行时"
|
||||
Code->>Compiler : const desktopEM = new EventBuilderImpl<IDesktopEvent>()
|
||||
Compiler->>Compiler : 类型检查:验证IDesktopEvent结构
|
||||
Compiler-->>Code : 返回类型安全的事件管理器实例
|
||||
Code->>Runtime : desktopEM.addEventListener('desktopAppPosChange', handler)
|
||||
Runtime->>Runtime : 存储事件处理器
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L15-L15)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
|
||||
**Section sources**
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L15-L15)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
|
||||
## 应用图标位置变化事件语义解析
|
||||
|
||||
`desktopAppPosChange`事件承载着桌面应用图标位置变更的核心语义。其参数类型`IDesktopAppIcon`精确描述了图标的元数据:
|
||||
|
||||
| 属性 | 类型 | 描述 |
|
||||
|------|------|------|
|
||||
| `name` | string | 图标名称,唯一标识 |
|
||||
| `icon` | string | 图标资源路径或标识符 |
|
||||
| `path` | string | 点击后启动的应用路径 |
|
||||
| `x` | number | 在网格布局中的列索引(从1开始) |
|
||||
| `y` | number | 在网格布局中的行索引(从1开始) |
|
||||
|
||||
当用户拖动图标并释放时,系统会构造包含新坐标(x,y)的`IDesktopAppIcon`对象,并通过`desktopEM.notifyEvent`触发此事件,通知所有监听者更新UI状态。
|
||||
|
||||
**Section sources**
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L11-L11)
|
||||
- [IDesktopAppIcon.ts](file://src/ui/types/IDesktopAppIcon.ts#L3-L14)
|
||||
|
||||
## 桌面容器中的事件监听实践
|
||||
|
||||
在`useDesktopContainerInit`这一组合式函数中,展示了如何在桌面容器初始化过程中订阅`desktopAppPosChange`事件以实现UI同步更新。
|
||||
|
||||
虽然当前代码未直接展示订阅逻辑,但根据上下文可推断出典型使用模式如下:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["组件挂载 onMounted"] --> B["订阅 desktopAppPosChange 事件"]
|
||||
B --> C["接收 IDesktopAppIcon 数据"]
|
||||
C --> D["更新 appIconsRef 状态"]
|
||||
D --> E["触发 Vue 响应式更新"]
|
||||
E --> F["UI 自动重渲染"]
|
||||
G["图标拖拽结束"] --> H["发布 desktopAppPosChange 事件"]
|
||||
H --> B
|
||||
```
|
||||
|
||||
理想情况下,在`onMounted`钩子内应调用:
|
||||
```ts
|
||||
desktopEM.addEventListener('desktopAppPosChange', (info) => {
|
||||
const index = appIconsRef.value.findIndex(icon => icon.name === info.name);
|
||||
if (index !== -1) {
|
||||
appIconsRef.value[index] = { ...info };
|
||||
}
|
||||
});
|
||||
```
|
||||
从而建立从事件到视图的完整响应链路。
|
||||
|
||||
**Section sources**
|
||||
- [useDesktopContainerInit.ts](file://src/ui/desktop-container/useDesktopContainerInit.ts#L0-L164)
|
||||
|
||||
## 拖拽结束时的事件发布机制
|
||||
|
||||
`desktopEM`的事件发布时机严格遵循用户交互生命周期。在应用图标的拖拽组件中,应在拖拽结束(dragend)事件处理器中调用:
|
||||
|
||||
```ts
|
||||
desktopEM.notifyEvent('desktopAppPosChange', currentIconInfo);
|
||||
```
|
||||
|
||||
此时传递的`currentIconInfo`必须是完整的`IDesktopAppIcon`对象,包含更新后的`x`和`y`坐标。该调用会遍历所有注册的监听器,并按顺序执行其回调函数,实现多播通知。
|
||||
|
||||
发布流程的关键特性包括:
|
||||
- **同步执行**:所有监听器在同一线程内依次调用
|
||||
- **异常隔离**:单个监听器错误不会中断其他监听器执行
|
||||
- **一次性监听支持**:可通过`once: true`选项注册只触发一次的监听器
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant DragComponent as "拖拽组件"
|
||||
participant DesktopEM as "desktopEM"
|
||||
participant ListenerA as "监听器A"
|
||||
participant ListenerB as "监听器B"
|
||||
DragComponent->>DesktopEM : notifyEvent('desktopAppPosChange', info)
|
||||
DesktopEM->>ListenerA : 执行回调函数
|
||||
ListenerA-->>DesktopEM : 完成
|
||||
DesktopEM->>ListenerB : 执行回调函数
|
||||
ListenerB-->>DesktopEM : 完成
|
||||
DesktopEM-->>DragComponent : 通知完成
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L75-L90)
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts#L15-L15)
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L75-L90)
|
||||
|
||||
## 总结
|
||||
|
||||
`DesktopEventManager`通过泛型化继承核心事件总线`EventBuilderImpl`,成功构建了一个类型安全、语义清晰的领域事件系统。`IDesktopEvent`接口明确定义了`desktopAppPosChange`事件及其`IDesktopAppIcon`参数结构,`desktopEM`实例作为全局事件枢纽,在拖拽结束时精准发布坐标变更事件。尽管当前`useDesktopContainerInit`中尚未体现订阅逻辑,但整个架构已为实现响应式桌面UI奠定了坚实基础。
|
||||
186
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口关闭事件.md
Normal file
186
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口关闭事件.md
Normal file
@@ -0,0 +1,186 @@
|
||||
# 窗口关闭事件
|
||||
|
||||
<cite>
|
||||
**Referenced Files in This Document **
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts)
|
||||
- [DesktopEventManager.ts](file://src/events/DesktopEventManager.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [核心职责与生命周期管理](#核心职责与生命周期管理)
|
||||
3. [事件定义与接口规范](#事件定义与接口规范)
|
||||
4. [事件注册与监听机制](#事件注册与监听机制)
|
||||
5. [事件广播与跨组件通信](#事件广播与跨组件通信)
|
||||
6. [资源清理与内存泄漏防护](#资源清理与内存泄漏防护)
|
||||
7. [完整示例:带确认对话框的关闭流程](#完整示例:带确认对话框的关闭流程)
|
||||
8. [总结](#总结)
|
||||
|
||||
## 简介
|
||||
|
||||
`windowFormClose` 事件是 Vue 桌面应用中用于管理窗口实例销毁的核心机制。当用户点击窗口右上角的关闭按钮时,系统会触发该事件,并携带目标窗口的唯一标识符(ID),以精确地定位并销毁对应的窗口实例。此事件不仅负责 UI 层面的 DOM 移除,还承担着状态存储更新、资源释放以及防止内存泄漏的重要职责。
|
||||
|
||||
本文档将深入解析 `windowFormClose` 事件的整个生命周期,涵盖其定义、注册、广播及处理过程,并说明如何通过 `wfem`(Window Form Event Manager)进行监听器注册,集成用户确认逻辑,并确保系统的安全性和一致性。
|
||||
|
||||
## 核心职责与生命周期管理
|
||||
|
||||
`windowFormClose` 事件在窗口关闭流程中扮演着中枢角色,其生命周期贯穿从用户交互到最终资源回收的全过程:
|
||||
|
||||
1. **触发阶段**:由用户点击关闭按钮发起,事件携带窗口 ID 作为参数。
|
||||
2. **广播阶段**:通过 `wfem.notifyEvent('windowFormClose', id)` 将事件分发至所有注册的监听器。
|
||||
3. **处理阶段**:各组件根据自身业务逻辑响应事件,执行如显示确认对话框、保存未提交数据等操作。
|
||||
4. **清理阶段**:完成必要检查后,执行 DOM 节点移除、状态 store 更新和相关资源释放。
|
||||
5. **终止阶段**:确保所有引用被清除,避免因闭包或事件监听器残留导致的内存泄漏。
|
||||
|
||||
该事件的设计遵循单一职责原则,专注于“关闭”这一核心动作,同时通过松耦合的发布-订阅模式实现跨组件协作。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L27-L27)
|
||||
|
||||
## 事件定义与接口规范
|
||||
|
||||
`windowFormClose` 事件在 `IWindowFormEvent` 接口中明确定义,位于 `src/events/WindowFormEventManager.ts` 文件中。该接口继承自通用事件映射类型 `IEventMap`,并声明了多个与窗口操作相关的事件处理器签名。
|
||||
|
||||
```typescript
|
||||
interface IWindowFormEvent extends IEventMap {
|
||||
/**
|
||||
* 窗口关闭
|
||||
* @param id 窗口id
|
||||
*/
|
||||
windowFormClose: (id: string) => void;
|
||||
// 其他事件...
|
||||
}
|
||||
```
|
||||
|
||||
此定义明确了以下关键信息:
|
||||
- **事件名称**:`windowFormClose`
|
||||
- **参数类型**:单个字符串类型的 `id`,用于唯一标识待关闭的窗口实例。
|
||||
- **返回类型**:`void`,表示该事件不期望返回值,主要用于触发副作用。
|
||||
|
||||
这种强类型的接口设计保证了事件使用的安全性,编译器能够在开发阶段捕获类型错误。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class IWindowFormEvent {
|
||||
+windowFormMinimize(id : string) void
|
||||
+windowFormMaximize(id : string) void
|
||||
+windowFormRestore(id : string) void
|
||||
+windowFormClose(id : string) void
|
||||
+windowFormFocus(id : string) void
|
||||
+windowFormDataUpdate(data : IWindowFormDataUpdateParams) void
|
||||
+windowFormCreated() void
|
||||
}
|
||||
class IEventMap {
|
||||
<<interface>>
|
||||
}
|
||||
IWindowFormEvent --|> IEventMap : 继承
|
||||
```
|
||||
|
||||
**Diagram sources **
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L7-L42)
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L7-L42)
|
||||
|
||||
## 事件注册与监听机制
|
||||
|
||||
系统使用 `wfem`(`WindowFormEventManager` 的实例)作为 `windowFormClose` 事件的管理中心。开发者可通过 `addEventListener` 方法注册监听器,语法如下:
|
||||
|
||||
```typescript
|
||||
wfem.addEventListener('windowFormClose', (id) => {
|
||||
// 处理关闭逻辑
|
||||
});
|
||||
```
|
||||
|
||||
`wfem` 是基于 `EventBuilderImpl` 类构建的事件总线实例,它提供了类型安全的事件注册、移除和通知功能。`addEventListener` 方法支持可选参数,例如 `immediate` 可用于在注册时立即执行一次回调,`once` 则确保监听器仅响应一次事件。
|
||||
|
||||
这种机制允许任意组件在需要时订阅关闭事件,而无需直接依赖具体的窗口管理逻辑,实现了高度的解耦。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant UI as UI组件
|
||||
participant Wfem as wfem(事件管理器)
|
||||
participant Listener as 关闭监听器
|
||||
User->>UI : 点击关闭按钮
|
||||
UI->>Wfem : notifyEvent("windowFormClose", windowId)
|
||||
Wfem->>Listener : 执行所有注册的监听器
|
||||
Listener-->>Wfem : 返回
|
||||
Wfem-->>UI : 事件处理完毕
|
||||
```
|
||||
|
||||
**Diagram sources **
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
|
||||
## 事件广播与跨组件通信
|
||||
|
||||
`windowFormClose` 事件的广播能力由 `EventBuilderImpl` 类的 `notifyEvent` 方法实现。该方法遍历内部存储的所有监听器,并按顺序调用它们。这种发布-订阅模式是实现跨组件通信的关键。
|
||||
|
||||
其优势在于:
|
||||
- **低耦合**:发送者(如窗口控件)无需知道接收者的存在,只需关注事件的发出。
|
||||
- **高内聚**:每个监听器只需关注与自己相关的业务逻辑,例如一个监听器负责弹出确认框,另一个负责清理定时器。
|
||||
- **可扩展性**:可以轻松添加新的监听器来增强关闭流程的功能,而无需修改现有代码。
|
||||
|
||||
事件广播确保了所有相关方都能及时收到关闭通知,从而协同完成复杂的清理任务,维护了系统状态的一致性。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
A[窗口A] --> |notifyEvent| B(wfem)
|
||||
C[窗口B] --> |notifyEvent| B
|
||||
D[其他组件] --> |notifyEvent| B
|
||||
B --> E[监听器1]
|
||||
B --> F[监听器2]
|
||||
B --> G[监听器N]
|
||||
```
|
||||
|
||||
**Diagram sources **
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
|
||||
## 资源清理与内存泄漏防护
|
||||
|
||||
正确处理 `windowFormClose` 事件是防止内存泄漏的核心环节。一个完整的清理流程应包括:
|
||||
|
||||
1. **DOM 移除**:从虚拟 DOM 和真实 DOM 中卸载窗口及其子组件。
|
||||
2. **状态更新**:在全局状态 store(如 Pinia 或 Vuex)中移除对应窗口的状态条目。
|
||||
3. **事件解绑**:移除该窗口实例上注册的所有自定义事件监听器。
|
||||
4. **资源释放**:清除与该窗口关联的定时器(`setInterval`, `setTimeout`)、WebSocket 连接或其他长生命周期对象。
|
||||
|
||||
`EventBuilderImpl` 内部通过 `Set` 数据结构管理监听器,并在每次事件通知后检查 `once` 标志,自动清理一次性监听器。此外,`destroy` 方法可用于彻底清空所有事件处理器,为整个事件管理器的销毁提供支持。
|
||||
|
||||
**Section sources**
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
|
||||
## 完整示例:带确认对话框的关闭流程
|
||||
|
||||
以下是一个典型的 `windowFormClose` 事件监听器实现,集成了用户确认对话框和资源释放逻辑:
|
||||
|
||||
```typescript
|
||||
wfem.addEventListener('windowFormClose', async (id) => {
|
||||
const shouldClose = await showConfirmDialog(`确定要关闭窗口 ${id} 吗?`);
|
||||
if (!shouldClose) return; // 用户取消,中断关闭流程
|
||||
|
||||
// 1. 清理特定于该窗口的资源
|
||||
cleanupWindowResources(id);
|
||||
|
||||
// 2. 从状态store中移除窗口记录
|
||||
windowStore.removeWindow(id);
|
||||
|
||||
// 3. 触发DOM移除(通常由组件自身在状态变更后自动处理)
|
||||
console.log(`窗口 ${id} 已成功关闭并清理`);
|
||||
}, { once: false }); // 保持监听器长期有效
|
||||
```
|
||||
|
||||
在此示例中:
|
||||
- 使用异步函数等待用户确认。
|
||||
- 若用户取消,则直接返回,阻止后续清理操作。
|
||||
- 按照逻辑顺序执行资源清理、状态更新等步骤。
|
||||
- 监听器设置为持久性(`once: false`),以便能响应未来可能发生的同类型事件。
|
||||
|
||||
## 总结
|
||||
|
||||
`windowFormClose` 事件是 Vue 桌面应用中窗口管理模块的基石。它通过清晰的接口定义、高效的事件广播机制和严谨的资源清理策略,确保了窗口实例能够被安全、可靠地销毁。借助 `wfem` 事件总线,系统实现了组件间的松耦合通信,使得复杂的关闭流程可以被分解为多个独立、可维护的监听器。遵循本文档所述的最佳实践,可以有效避免内存泄漏,保障应用的长期稳定运行。
|
||||
76
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口创建完成事件.md
Normal file
76
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口创建完成事件.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# 窗口创建完成事件
|
||||
|
||||
<cite>
|
||||
**本文档引用文件**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [事件语义与调用时机](#事件语义与调用时机)
|
||||
2. [应用场景分析](#应用场景分析)
|
||||
3. [事件监听代码范例](#事件监听代码范例)
|
||||
4. [生命周期时序关系](#生命周期时序关系)
|
||||
|
||||
## 事件语义与调用时机
|
||||
|
||||
`windowFormCreated` 事件在新窗口实例成功挂载并完成首次渲染后触发,标志着窗口已完全初始化并可交互。该事件不携带任何参数,作为全局窗口创建完成的信号。
|
||||
|
||||
根据 `WindowFormEventManager.ts` 中的定义,此事件是 `IWindowFormEvent` 接口的一部分,由 `wfem` 事件管理器负责分发。虽然当前实现中未直接显示触发逻辑,但结合 `WindowService.ts` 的窗口创建流程可知,该事件应在 `createWindow` 方法执行完毕、DOM 元素已添加至页面且应用内容加载完成后被通知。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L41-L41)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L83-L118)
|
||||
|
||||
## 应用场景分析
|
||||
|
||||
### 启动引导
|
||||
在系统启动或模块初始化过程中,通过监听 `windowFormCreated` 事件可以确保所有核心窗口均已准备就绪,从而安全地执行后续引导逻辑,如自动聚焦主窗口或初始化关联组件。
|
||||
|
||||
### 任务栏更新
|
||||
当新窗口创建完成后,任务栏组件可通过监听该事件实时更新其窗口列表,确保用户界面状态与实际运行情况保持同步。
|
||||
|
||||
### 快捷方式激活
|
||||
从桌面快捷方式启动应用时,该事件可用于确认目标窗口已成功打开,进而执行焦点切换或动画展示等增强用户体验的操作。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L41-L41)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L83-L118)
|
||||
|
||||
## 事件监听代码范例
|
||||
|
||||
以下为监听 `windowFormCreated` 事件并执行后续操作的典型代码模式:
|
||||
|
||||
```typescript
|
||||
import { wfem } from '@/events/WindowFormEventManager'
|
||||
|
||||
// 监听窗口创建完成事件
|
||||
wfem.addEventListener('windowFormCreated', () => {
|
||||
// 执行日志记录
|
||||
console.log('新窗口创建完成')
|
||||
|
||||
// 执行自动聚焦或其他初始化操作
|
||||
// focusMainWindow()
|
||||
})
|
||||
```
|
||||
|
||||
此类监听器常用于执行一次性初始化任务,例如设置默认焦点、注册快捷键、加载用户偏好设置或发送性能监控指标。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L83-L118)
|
||||
|
||||
## 生命周期时序关系
|
||||
|
||||
`windowFormCreated` 事件作为窗口生命周期的起点,在以下关键阶段之后发生:
|
||||
1. **CREATING**:窗口对象创建
|
||||
2. **LOADING**:DOM 元素构建与插入
|
||||
3. **ACTIVE**:窗口激活并获得焦点
|
||||
|
||||
它早于任何用户交互事件(如 `windowFormFocus`)和状态变更事件(如 `windowFormMinimize`),是首个表示窗口已进入稳定可用状态的全局事件。
|
||||
|
||||
与其他事件相比,`windowFormCreated` 是唯一无参数的创建完成信号,而其他事件如 `windowFormDataUpdate` 则携带具体的状态数据。这种设计使其成为理想的初始化钩子点。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L41-L41)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L83-L118)
|
||||
149
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口数据更新事件.md
Normal file
149
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口数据更新事件.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# 窗口数据更新事件
|
||||
|
||||
<cite>
|
||||
**本文档引用文件**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [IWindowFormDataUpdateParams接口字段语义解析](#iwindowformdataupdateparams接口字段语义解析)
|
||||
3. [TWindowFormState类型关联说明](#twindowformstatetype类型关联说明)
|
||||
4. [窗口拖拽、缩放与状态切换中的统一元数据发送机制](#窗口拖拽缩放与状态切换中的统一元数据发送机制)
|
||||
5. [接收端批量更新UI的TypeScript示例](#接收端批量更新ui的typescript示例)
|
||||
6. [高频更新性能优化建议:防抖策略](#高频更新性能优化建议防抖策略)
|
||||
7. [窗口状态实时同步与持久化存储支持机制](#窗口状态实时同步与持久化存储支持机制)
|
||||
|
||||
## 简介
|
||||
`windowFormDataUpdate` 事件是桌面应用中用于传递窗口最新元数据的核心通信机制。该事件在窗口发生位置移动、尺寸调整或状态变更(如最小化、最大化)时触发,通过 `IWindowFormDataUpdateParams` 接口统一封装窗口的ID、状态、尺寸和坐标信息,并广播至所有监听者。此设计实现了窗口状态变化的集中通知与响应,为UI同步、布局管理及状态持久化提供了基础支撑。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L37-L37)
|
||||
|
||||
## IWindowFormDataUpdateParams接口字段语义解析
|
||||
`IWindowFormDataUpdateParams` 接口定义了窗口更新事件所携带的数据结构,包含以下关键字段:
|
||||
|
||||
- **id**: 字符串类型,表示窗口的唯一标识符。该ID由系统生成并贯穿窗口生命周期,用于精确识别和定位特定窗口实例。
|
||||
- **state**: 枚举类型 `TWindowFormState`,表示当前窗口的状态,包括 `'default'`(默认)、`'minimized'`(最小化)、`'maximized'`(最大化)三种可能值。
|
||||
- **width**: 数字类型,表示窗口当前的宽度(单位:像素),反映窗口水平方向的实际尺寸。
|
||||
- **height**: 数字类型,表示窗口当前的高度(单位:像素),反映窗口垂直方向的实际尺寸。
|
||||
- **x**: 数字类型,表示窗口左上角相对于屏幕原点的X轴坐标(单位:像素),用于确定窗口的水平位置。
|
||||
- **y**: 数字类型,表示窗口左上角相对于屏幕原点的Y轴坐标(单位:像素),用于确定窗口的垂直位置。
|
||||
|
||||
这些字段共同构成了窗口的完整元数据快照,确保接收方能够准确还原窗口的视觉表现和行为状态。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L44-L57)
|
||||
|
||||
## TWindowFormState类型关联说明
|
||||
`TWindowFormState` 是一个字符串联合类型,明确定义了窗口可处于的三种核心状态:
|
||||
- `'default'`: 窗口处于正常显示状态,既非最大化也非最小化。
|
||||
- `'minimized'`: 窗口被最小化,通常从主视图隐藏,仅在任务栏或启动器中保留图标。
|
||||
- `'maximized'`: 窗口被最大化,占据除任务栏外的整个屏幕空间。
|
||||
|
||||
该类型与 `IWindowFormDataUpdateParams.state` 字段直接关联,作为事件数据的一部分,在窗口状态发生变化时(例如用户点击最大化按钮),新的状态值将被封装进事件参数中并广播出去。这种强类型的约束保证了状态传递的准确性与一致性。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L9-L9)
|
||||
|
||||
## 窗口拖拽、缩放与状态切换中的统一元数据发送机制
|
||||
无论窗口因何种操作而改变其外观或状态,系统均通过 `windowFormDataUpdate` 事件统一发送最新的元数据。具体流程如下:
|
||||
|
||||
1. **拖拽操作**:当用户拖动窗口标题栏时,鼠标移动事件会持续更新窗口的 `x` 和 `y` 坐标。在每次坐标更新后,系统调用 `setActiveWindow` 激活该窗口,并最终通过事件总线触发 `windowFormDataUpdate`,附带更新后的坐标、尺寸及当前状态。
|
||||
2. **缩放操作**:当用户调整窗口大小时,`setWindowSize` 方法被调用以更新 `width` 和 `height`。此方法不仅修改DOM样式,还会通知事件总线,从而触发包含新尺寸的 `windowFormDataUpdate` 事件。
|
||||
3. **状态切换**:无论是最小化、最大化还是还原操作,都会先调用 `updateWindowState` 修改内部状态机,随后根据新状态调整DOM表现(如隐藏元素或全屏展示)。最后,系统发出 `windowFormDataUpdate` 事件,其中 `state` 字段反映最新状态,同时附带相应的坐标和尺寸信息。
|
||||
|
||||
这一机制确保了所有窗口变更都通过单一入口进行通知,简化了状态管理逻辑,避免了多事件源导致的不一致问题。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[用户操作] --> B{操作类型}
|
||||
B --> |拖拽| C[更新 x, y]
|
||||
B --> |缩放| D[更新 width, height]
|
||||
B --> |状态切换| E[更新 state]
|
||||
C --> F[调用 setActiveWindow]
|
||||
D --> G[调用 setWindowSize]
|
||||
E --> H[调用 updateWindowState]
|
||||
F --> I[触发 windowFormDataUpdate]
|
||||
G --> I
|
||||
H --> I
|
||||
I --> J[接收端更新UI]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L512-L552)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L248-L304)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L179-L213)
|
||||
|
||||
**Section sources**
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L512-L552)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L248-L304)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L179-L213)
|
||||
|
||||
## 接收端批量更新UI的TypeScript示例
|
||||
接收 `windowFormDataUpdate` 事件后,应使用接收到的完整数据对象一次性批量更新UI,避免逐个属性设置带来的性能开销和视觉闪烁。以下为推荐的处理方式:
|
||||
|
||||
```typescript
|
||||
wfem.addEventListener('windowFormDataUpdate', (data) => {
|
||||
const { id, state, width, height, x, y } = data;
|
||||
const windowElement = document.getElementById(`window-${id}`);
|
||||
|
||||
if (!windowElement) return;
|
||||
|
||||
// 批量更新样式属性
|
||||
Object.assign(windowElement.style, {
|
||||
width: `${width}px`,
|
||||
height: `${height}px`,
|
||||
left: `${x}px`,
|
||||
top: `${y}px`,
|
||||
display: state === 'minimized' ? 'none' : 'block'
|
||||
});
|
||||
|
||||
// 根据状态添加CSS类以支持主题化样式
|
||||
windowElement.classList.toggle('maximized', state === 'maximized');
|
||||
windowElement.classList.toggle('minimized', state === 'minimized');
|
||||
windowElement.classList.toggle('default', state === 'default');
|
||||
});
|
||||
```
|
||||
|
||||
上述代码利用 `Object.assign` 对目标DOM元素的样式进行原子性更新,确保浏览器只进行一次重排(reflow)和重绘(repaint),从而提升渲染效率。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L37-L37)
|
||||
|
||||
## 高频更新性能优化建议:防抖策略
|
||||
由于拖拽和缩放操作会产生大量连续的 `windowFormDataUpdate` 事件,若不对处理函数加以节流,可能导致UI线程阻塞或频繁重绘,影响用户体验。为此,建议对接收端的事件处理器应用防抖(debounce)技术:
|
||||
|
||||
```typescript
|
||||
function debounce<T extends (...args: any[]) => void>(func: T, delay: number): T {
|
||||
let timeoutId: ReturnType<typeof setTimeout>;
|
||||
return function (this: any, ...args: any[]) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => func.apply(this, args), delay);
|
||||
} as T;
|
||||
}
|
||||
|
||||
const debouncedHandler = debounce((data: IWindowFormDataUpdateParams) => {
|
||||
// 执行UI更新逻辑
|
||||
}, 16); // 约60fps的间隔
|
||||
|
||||
wfem.addEventListener('windowFormDataUpdate', debouncedHandler);
|
||||
```
|
||||
|
||||
通过设置约16毫秒的延迟(对应60Hz刷新率),可以有效过滤掉中间过渡状态,仅处理最终稳定的位置或尺寸,显著降低计算负担并提升流畅度。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L44-L57)
|
||||
|
||||
## 窗口状态实时同步与持久化存储支持机制
|
||||
`windowFormDataUpdate` 事件不仅是UI更新的驱动源,也为跨组件通信和状态持久化提供了可靠的数据通道。任何需要感知窗口状态的模块(如任务栏、窗口管理器、布局保存服务)均可订阅此事件,实现状态的实时同步。
|
||||
|
||||
此外,通过监听该事件,可将窗口的 `id`、`state`、`width`、`height`、`x`、`y` 等元数据记录到本地存储(如localStorage)或远程服务器,实现用户偏好的记忆功能。例如,在用户下次启动应用时,系统可根据存储的历史数据恢复窗口的原始位置和大小,提供一致的使用体验。
|
||||
|
||||
该事件的设计使得状态采集与业务逻辑解耦,任何持久化逻辑只需作为事件观察者存在,无需侵入窗口控制核心代码,符合关注点分离原则。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L37-L37)
|
||||
- [WindowService.ts](file://src/services/WindowService.ts#L67-L118)
|
||||
114
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口最大化事件.md
Normal file
114
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口最大化事件.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# 窗口最大化事件
|
||||
|
||||
<cite>
|
||||
**本文档引用文件**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts)
|
||||
- [basic.css](file://src/css/basic.css)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [引言](#引言)
|
||||
2. [事件触发机制](#事件触发机制)
|
||||
3. [状态映射与UI响应](#状态映射与ui响应)
|
||||
4. [CSS视觉变换实现](#css视觉变换实现)
|
||||
5. [TypeScript代码范例](#typescript代码范例)
|
||||
6. [多窗口协调机制](#多窗口协调机制)
|
||||
7. [总结](#总结)
|
||||
|
||||
## 引言
|
||||
本节全面阐述`windowFormMaximize`事件的触发条件与交互逻辑。当用户点击窗口最大化按钮时,系统将广播该事件并携带窗口ID至所有订阅者,驱动UI进入全屏布局模式。此机制是桌面级应用中实现窗口管理的核心部分。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L1-L60)
|
||||
|
||||
## 事件触发机制
|
||||
`windowFormMaximize`事件定义于`IWindowFormEvent`接口中,其函数签名接受一个字符串类型的窗口ID参数:
|
||||
|
||||
```ts
|
||||
windowFormMaximize: (id: string) => void;
|
||||
```
|
||||
|
||||
该事件由全局事件管理器`wfem`(即`EventBuilderImpl<IWindowFormEvent>`实例)负责分发。当用户交互触发最大化行为时,调用`notifyEvent('windowFormMaximize', windowId)`方法,向所有监听此事件的组件广播通知。
|
||||
|
||||
事件系统基于观察者模式实现,支持动态注册和注销监听器,并可通过配置项实现立即执行、单次监听等功能。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L17-L17)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
|
||||
## 状态映射与UI响应
|
||||
`windowFormMaximize`事件与`TWindowFormState`类型中的`maximized`状态存在直接映射关系。`TWindowFormState`定义如下:
|
||||
|
||||
```ts
|
||||
export type TWindowFormState = 'default' | 'minimized' | 'maximized';
|
||||
```
|
||||
|
||||
当事件被触发后,相关组件会更新对应窗口的状态为`maximized`,并通过响应式机制驱动视图重绘。通常结合`windowFormDataUpdate`事件同步窗口尺寸与位置信息,确保状态一致性。
|
||||
|
||||
状态变更不仅影响当前窗口的显示模式,还可能触发任务栏图标高亮、Z轴层级调整等副作用,以保证用户体验的一致性。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L9-L9)
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L50-L55)
|
||||
|
||||
## CSS视觉变换实现
|
||||
窗口最大化过程中的视觉效果主要通过CSS变换实现。虽然具体样式未在核心逻辑文件中体现,但可推断其依赖以下机制:
|
||||
|
||||
- 使用`transform: scale()`或`width/height: 100%`实现尺寸扩展
|
||||
- 配合过渡动画(transition)实现平滑缩放
|
||||
- 利用`z-index`控制多窗口堆叠顺序
|
||||
- 可能结合`position: fixed`或`absolute`脱离文档流进行定位
|
||||
|
||||
基础样式文件`basic.css`提供了通用的盒模型重置、字体设置及响应式支持,为窗口动画提供稳定的样式环境。
|
||||
|
||||
**Section sources**
|
||||
- [basic.css](file://src/css/basic.css#L1-L134)
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
|
||||
## TypeScript代码范例
|
||||
使用`wfem`监听并处理最大化行为的标准TypeScript代码范例如下:
|
||||
|
||||
```ts
|
||||
// 订阅窗口最大化事件
|
||||
wfem.addEventListener('windowFormMaximize', (id: string) => {
|
||||
// 更新窗口状态
|
||||
const window = getWindowById(id);
|
||||
if (window) {
|
||||
window.state = 'maximized';
|
||||
// 触发DOM重绘
|
||||
redrawWindow(window);
|
||||
// 持久化状态(可选)
|
||||
saveWindowState(id, 'maximized');
|
||||
}
|
||||
});
|
||||
|
||||
// 发送最大化事件
|
||||
function maximizeWindow(id: string) {
|
||||
wfem.notifyEvent('windowFormMaximize', id);
|
||||
}
|
||||
```
|
||||
|
||||
建议在状态变更后调用重绘函数,并考虑将用户偏好(如是否最大化)持久化至`localStorage`,以便页面刷新后恢复。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L70-L75)
|
||||
|
||||
## 多窗口协调机制
|
||||
在多窗口堆叠场景下,`windowFormMaximize`事件起到关键协调作用。当某一窗口最大化时:
|
||||
|
||||
- 其他非最小化窗口应自动退至后台
|
||||
- 最大化窗口获得最高`z-index`层级
|
||||
- 任务栏对应图标处于激活状态
|
||||
- 若存在模态窗口,则需特殊处理避免遮挡
|
||||
|
||||
事件广播机制确保所有关注窗口状态的模块(如任务栏、窗口管理器、快捷键服务)能同步响应,维持系统整体状态一致。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L17-L17)
|
||||
- [DesktopContainer.vue](file://src/ui/desktop-container/DesktopContainer.vue#L1-L23)
|
||||
|
||||
## 总结
|
||||
`windowFormMaximize`事件作为窗口控制系统的重要组成部分,实现了从用户操作到UI响应的完整闭环。它通过标准化的事件总线机制解耦组件间通信,结合类型安全的状态定义与CSS视觉变换,构建出流畅且可维护的桌面级交互体验。在复杂多窗口环境中,该事件有效协调各组件行为,保障系统稳定性与一致性。
|
||||
96
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口最小化事件.md
Normal file
96
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口最小化事件.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# 窗口最小化事件
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [事件机制概述](#事件机制概述)
|
||||
2. [事件触发与参数传递](#事件触发与参数传递)
|
||||
3. [状态同步与枚举值应用](#状态同步与枚举值应用)
|
||||
4. [监听器注册与Pinia状态更新](#监听器注册与pinia状态更新)
|
||||
5. [事件解耦设计分析](#事件解耦设计分析)
|
||||
|
||||
## 事件机制概述
|
||||
|
||||
`windowFormMinimize` 事件是窗口管理系统中的核心交互事件之一,用于响应用户点击窗口最小化按钮的操作。该事件通过全局事件管理器 `wfem` 进行广播,采用发布-订阅模式实现组件间的松耦合通信。事件定义在 `IWindowFormEvent` 接口中,并由 `EventBuilderImpl` 类提供具体的事件注册与通知能力。
|
||||
|
||||
此事件机制的设计使得任意组件均可独立监听窗口最小化行为,而无需直接依赖窗口实例本身,从而提升了系统的可维护性与扩展性。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L12-L12)
|
||||
|
||||
## 事件触发与参数传递
|
||||
|
||||
当用户点击窗口的最小化按钮时,系统会调用 `wfem.notifyEvent('windowFormMinimize', id)` 方法触发该事件。其中 `id` 为窗口的唯一标识符(字符串类型),作为事件回调函数的参数传递给所有监听者。
|
||||
|
||||
事件的接口定义如下:
|
||||
```ts
|
||||
windowFormMinimize: (id: string) => void;
|
||||
```
|
||||
这确保了所有监听器都能接收到被最小化的窗口ID,进而执行相应的UI动画或逻辑处理。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L12-L12)
|
||||
|
||||
## 状态同步与枚举值应用
|
||||
|
||||
在接收到 `windowFormMinimize` 事件后,系统通常会将对应窗口的状态更新为 `'minimized'`。该状态值来源于 `TWindowFormState` 枚举类型,其定义如下:
|
||||
|
||||
```ts
|
||||
export type TWindowFormState = 'default' | 'minimized' | 'maximized';
|
||||
```
|
||||
|
||||
通过将窗口状态设置为 `'minimized'`,可以驱动视图层进行相应的渲染更新,例如隐藏窗口内容、在任务栏显示缩略图标等。这种基于枚举的状态管理模式增强了代码的可读性和类型安全性。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L9-L9)
|
||||
|
||||
## 监听器注册与Pinia状态更新
|
||||
|
||||
在Vue组件中,可通过 `wfem.addEventListener` 方法注册对 `windowFormMinimize` 事件的监听。典型用法如下所示:
|
||||
|
||||
```ts
|
||||
wfem.addEventListener('windowFormMinimize', (id: string) => {
|
||||
// 更新Pinia store中的窗口状态
|
||||
const windowStore = useWindowStore();
|
||||
windowStore.updateState(id, 'minimized');
|
||||
});
|
||||
```
|
||||
|
||||
上述代码展示了如何在事件回调中获取窗口ID并更新Pinia状态仓库中的窗口状态字段。这种方式实现了视图与状态的分离,符合现代前端架构的最佳实践。
|
||||
|
||||
尽管当前项目中未包含 `useWindowStore` 的具体实现,但基于现有技术栈(Vue + Pinia)可合理推断其存在类似的窗口状态管理模块。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L9-L9)
|
||||
|
||||
## 事件解耦设计分析
|
||||
|
||||
`windowFormMinimize` 事件体现了典型的事件驱动解耦设计。多个窗口组件可以各自注册监听器,独立响应最小化事件,而无需彼此知晓或直接通信。事件的发布者仅需调用 `notifyEvent`,由 `EventBuilderImpl` 负责遍历所有订阅者并执行回调。
|
||||
|
||||
该设计的优势包括:
|
||||
- **高内聚低耦合**:各组件专注于自身逻辑,不依赖其他窗口的状态。
|
||||
- **易于扩展**:新增窗口组件只需添加监听器即可参与事件流。
|
||||
- **便于测试**:事件监听逻辑可单独单元测试,无需完整UI环境。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[用户点击最小化按钮] --> B[触发 windowFormMinimize 事件]
|
||||
B --> C{通知所有监听者}
|
||||
C --> D[窗口A监听器: 执行最小化动画]
|
||||
C --> E[窗口B监听器: 更新状态为 minimized]
|
||||
C --> F[任务栏组件: 显示最小化图标]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L12-L12)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L50-L75)
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L50-L75)
|
||||
131
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口聚焦事件.md
Normal file
131
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口聚焦事件.md
Normal file
@@ -0,0 +1,131 @@
|
||||
<cite>
|
||||
**本文档中引用的文件**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts)
|
||||
- [useClickFocus.ts](file://src/common/hooks/useClickFocus.ts)
|
||||
- [useObservableVue.ts](file://src/common/hooks/useObservableVue.ts)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [窗口聚焦事件](#窗口聚焦事件)
|
||||
2. [用户交互背景](#用户交互背景)
|
||||
3. [技术实现机制](#技术实现机制)
|
||||
4. [多窗口层级管理](#多窗口层级管理)
|
||||
5. [Vue组件中的事件监听](#vue组件中的事件监听)
|
||||
6. [响应式状态更新](#响应式状态更新)
|
||||
7. [用户体验影响](#用户体验影响)
|
||||
|
||||
## 窗口聚焦事件
|
||||
|
||||
`windowFormFocus` 事件是桌面级Vue应用中用于管理窗口激活状态的核心事件。当用户点击或通过其他方式激活某个窗口时,该事件被触发并广播被激活窗口的唯一标识符(id),从而驱动UI层面对应的视觉反馈和状态变更。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L32-L32)
|
||||
|
||||
## 用户交互背景
|
||||
|
||||
在模拟传统桌面操作系统的Web应用中,用户期望拥有与原生应用一致的窗口交互体验。当用户点击一个处于非顶层的窗口时,该窗口应当自动移动到所有其他窗口的前面,并获得输入焦点。这种行为符合用户的直觉认知,即“所见即所得”的交互原则。`windowFormFocus` 事件正是为了捕捉这一关键的用户意图而设计的,它作为用户操作与系统响应之间的桥梁,确保了界面行为的可预测性和一致性。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L30-L34)
|
||||
|
||||
## 技术实现机制
|
||||
|
||||
`windowFormFocus` 事件的技术实现依赖于一个名为 `wfem` (Window Form Event Manager) 的全局事件管理器实例,该实例基于 `EventBuilderImpl` 类构建,提供了一套完整的发布-订阅模式接口。
|
||||
|
||||
事件的触发流程如下:
|
||||
1. **事件定义**:在 `IWindowFormEvent` 接口中明确定义了 `windowFormFocus(id: string)` 方法签名。
|
||||
2. **事件触发**:当检测到用户对特定窗口的点击操作时,业务逻辑代码会调用 `wfem.notifyEvent('windowFormFocus', windowId)` 来广播该事件。
|
||||
3. **事件监听**:任何需要对此事件做出反应的组件都可以通过 `wfem.addEventListener('windowFormFocus', callback)` 注册一个回调函数。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant Window as 窗口组件
|
||||
participant Hook as useClickFocus Hook
|
||||
participant EventManager as wfem (事件管理器)
|
||||
User->>Window : 点击窗口
|
||||
Window->>Hook : 触发内部处理
|
||||
Hook->>EventManager : 调用 notifyEvent('windowFormFocus', id)
|
||||
EventManager->>EventManager : 遍历所有监听器
|
||||
loop 通知所有订阅者
|
||||
EventManager-->>Subscriber : 执行注册的回调函数
|
||||
end
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
- [useClickFocus.ts](file://src/common/hooks/useClickFocus.ts#L13-L64)
|
||||
|
||||
## 多窗口层级管理
|
||||
|
||||
在存在多个重叠窗口的应用场景下,维护正确的渲染顺序至关重要。`windowFormFocus` 事件在此扮演了核心角色。每当该事件被触发,其携带的窗口ID会被传递给负责管理窗口栈的逻辑模块。该模块会根据ID找到对应的窗口元素,并将其CSS `z-index` 属性提升至最高层级,同时移除之前处于顶层窗口的焦点样式,并为当前窗口应用新的焦点样式(如高亮边框)。这一系列操作确保了被激活的窗口始终位于最前端,解决了视觉遮挡问题,使用户能够清晰地识别出当前正在操作的对象。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L30-L34)
|
||||
|
||||
## Vue组件中的事件监听
|
||||
|
||||
在Vue组件中监听 `windowFormFocus` 事件是一个标准的异步编程实践。开发者可以在组件的 `setup` 函数或 `onMounted` 生命周期钩子中,使用 `wfem.addEventListener` 方法注册一个监听器。最佳实践是将此逻辑封装在一个自定义Hook中,以保证代码的复用性和可维护性。例如,可以创建一个 `useWindowFocusListener` Hook,在组件挂载时订阅事件,并在组件卸载前 (`onBeforeUnmount`) 及时移除监听器,防止内存泄漏。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[组件挂载] --> B["调用 wfem.addEventListener('windowFormFocus', callback)"]
|
||||
B --> C[事件管理器注册回调]
|
||||
D[用户点击窗口] --> E["触发 wfem.notifyEvent('windowFormFocus', id)"]
|
||||
E --> F[事件管理器遍历并执行所有回调]
|
||||
F --> G[组件中的回调函数被调用]
|
||||
G --> H[更新组件内部状态]
|
||||
I[组件卸载] --> J["调用 wfem.removeEventListener 移除监听"]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
- [useClickFocus.ts](file://src/common/hooks/useClickFocus.ts#L13-L64)
|
||||
|
||||
## 响应式状态更新
|
||||
|
||||
为了实现高效且直观的状态管理,建议结合 `useObservableVue` 这一自定义Hook来处理 `windowFormFocus` 事件带来的状态变化。`useObservableVue` 将一个实现了 `IObservable<T>` 接口的可观察对象转换为Vue的响应式对象。当 `windowFormFocus` 事件触发时,其回调函数可以直接修改存储在可观察对象中的 `activeWindow` 状态。由于 `useObservableVue` 内部建立了双向同步机制,对可观察对象的任何修改都会立即反映到Vue的响应式系统中,从而自动触发相关组件的重新渲染,无需手动调用 `forceUpdate` 或进行复杂的 `$emit` 操作。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class IObservable~T~ {
|
||||
<<interface>>
|
||||
+subscribe(callback) : () => void
|
||||
+toRefsProxy() : T
|
||||
}
|
||||
class ObservableImpl~T~ {
|
||||
-state : T
|
||||
-observers : Set~() => void~
|
||||
+subscribe(callback) : () => void
|
||||
+toRefsProxy() : T
|
||||
+notify() : void
|
||||
}
|
||||
class useObservableVue {
|
||||
+useObservable(observable) : Reactive~T~
|
||||
}
|
||||
class Component {
|
||||
+setup()
|
||||
+template
|
||||
}
|
||||
IObservable~T~ <|.. ObservableImpl~T~ : 实现
|
||||
useObservableVue --> IObservable~T~ : 使用
|
||||
Component --> useObservableVue : 调用
|
||||
ObservableImpl~T~ --> Component : 通过响应式更新视图
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [useObservableVue.ts](file://src/common/hooks/useObservableVue.ts#L13-L87)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L1-L96)
|
||||
|
||||
## 用户体验影响
|
||||
|
||||
`windowFormFocus` 事件对桌面级应用的用户体验具有决定性的影响。它直接决定了应用是否能提供流畅、自然的多任务操作环境。一个正确实现的窗口聚焦机制能够:
|
||||
- **降低认知负荷**:用户无需思考哪个窗口是活动的,视觉反馈清晰明确。
|
||||
- **提高操作效率**:通过简单的点击即可切换上下文,符合肌肉记忆。
|
||||
- **增强应用可信度**:其行为与用户熟悉的操作系统保持一致,提升了应用的专业感和可靠性。
|
||||
|
||||
反之,如果该事件处理不当,例如出现窗口无法置顶、焦点丢失或样式错乱等问题,将严重破坏用户对应用的信任,导致挫败感和使用障碍。因此,确保 `windowFormFocus` 事件的稳定性和准确性是构建高质量桌面级Web应用的关键基石。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L30-L34)
|
||||
196
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口表单事件管理器.md
Normal file
196
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口表单事件管理器.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# 窗口表单事件管理器
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts)
|
||||
- [IEventBuilder.ts](file://src/events/IEventBuilder.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [窗口生命周期事件体系](#窗口生命周期事件体系)
|
||||
3. [IWindowFormDataUpdateParams数据结构分析](#iwindowformdataupdateparams数据结构分析)
|
||||
4. [wfem实例共享通信机制](#wfem实例共享通信机制)
|
||||
5. [Vue组件中事件监听代码范例](#vue组件中事件监听代码范例)
|
||||
6. [事件解耦带来的低耦合优势](#事件解耦带来的低耦合优势)
|
||||
|
||||
## 简介
|
||||
本系统通过`WindowFormEventManager`模块提供了一套完整的窗口生命周期事件管理体系,用于统一管理桌面应用中各类窗口的状态变化与用户交互行为。该体系基于观察者模式实现,支持多个窗口组件之间高效、安全地进行状态同步和通信。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L1-L60)
|
||||
|
||||
## 窗口生命周期事件体系
|
||||
系统定义了七种核心窗口事件,分别对应不同的用户操作或状态变更场景:
|
||||
|
||||
### windowFormMinimize(窗口最小化)
|
||||
当用户点击窗口最小化按钮时触发,通知相关组件当前窗口已进入最小化状态。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L10-L13)
|
||||
|
||||
### windowFormMaximize(窗口最大化)
|
||||
当用户点击窗口最大化按钮时触发,表示窗口已切换至全屏展示模式。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L15-L18)
|
||||
|
||||
### windowFormRestore(窗口还原)
|
||||
在窗口处于最大化或最小化状态下,用户执行还原操作时触发,表明窗口恢复为正常尺寸。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L20-L23)
|
||||
|
||||
### windowFormClose(窗口关闭)
|
||||
用户请求关闭窗口时触发,可用于执行清理逻辑或确认提示。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L25-L28)
|
||||
|
||||
### windowFormFocus(窗口聚焦)
|
||||
当窗口获得焦点(即被激活)时触发,常用于高亮显示当前活动窗口。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L30-L33)
|
||||
|
||||
### windowFormDataUpdate(窗口数据更新)
|
||||
每当窗口的位置、大小或状态发生变化时触发,携带完整的窗口元信息。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L35-L39)
|
||||
|
||||
### windowFormCreated(窗口创建完成)
|
||||
新窗口初始化完毕后触发一次,标志窗口已准备就绪可交互。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L41-L43)
|
||||
|
||||
## IWindowFormDataUpdateParams数据结构分析
|
||||
此接口定义了窗口状态更新时传递的数据结构,各字段含义如下:
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| id | string | 唯一标识一个窗口实例的ID |
|
||||
| state | TWindowFormState | 当前窗口的视觉状态 |
|
||||
| width | number | 窗口当前像素宽度 |
|
||||
| height | number | 窗口当前像素高度 |
|
||||
| x | number | 窗口左上角相对于屏幕的X坐标 |
|
||||
| y | number | 窗口左上角相对于屏幕的Y坐标 |
|
||||
|
||||
其中,`TWindowFormState` 是一个联合类型,定义于 `WindowFormTypes.ts` 文件中,包含三种可能取值:
|
||||
- `'default'`:默认状态(正常大小)
|
||||
- `'minimized'`:最小化状态
|
||||
- `'maximized'`:最大化状态
|
||||
|
||||
这些字段共同构成了窗口的完整状态快照,便于其他组件根据最新布局信息做出响应。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class IWindowFormDataUpdateParams {
|
||||
+id : string
|
||||
+state : TWindowFormState
|
||||
+width : number
|
||||
+height : number
|
||||
+x : number
|
||||
+y : number
|
||||
}
|
||||
class TWindowFormState {
|
||||
<<type>>
|
||||
'default'
|
||||
'minimized'
|
||||
'maximized'
|
||||
}
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L44-L57)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L9-L9)
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L44-L57)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L9-L9)
|
||||
|
||||
## wfem实例共享通信机制
|
||||
`wfem` 是一个全局唯一的 `EventBuilderImpl<IWindowFormEvent>` 实例,作为事件中心被所有窗口组件共享使用。其工作原理如下:
|
||||
|
||||
1. **事件注册**:任意组件可通过 `wfem.addEventListener(eventName, handler)` 订阅特定事件。
|
||||
2. **事件分发**:当窗口状态改变时,调用 `wfem.notifyEvent(eventName, args)` 广播事件。
|
||||
3. **跨组件通信**:不同组件间无需直接引用,仅通过事件总线即可实现松散耦合的状态同步。
|
||||
|
||||
这种设计使得各个窗口组件可以独立开发、测试和维护,同时又能实时感知彼此的状态变化。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant ComponentA as 组件A
|
||||
participant ComponentB as 组件B
|
||||
participant Wfem as wfem事件中心
|
||||
ComponentA->>Wfem : addEventListener("focus", handler)
|
||||
ComponentB->>Wfem : addEventListener("close", handler)
|
||||
Note over Wfem : 多个组件注册监听
|
||||
Window->>Wfem : notifyEvent("focus", "win123")
|
||||
Wfem->>ComponentA : 执行handler("win123")
|
||||
Window->>Wfem : notifyEvent("close", "win123")
|
||||
Wfem->>ComponentB : 执行handler("win123")
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L1-L95)
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
|
||||
## Vue组件中事件监听代码范例
|
||||
以下是在Vue 3组件中监听窗口聚焦与关闭事件的典型用法:
|
||||
|
||||
```typescript
|
||||
import { onMounted, onBeforeUnmount } from 'vue';
|
||||
import { wfem } from '@/events/WindowFormEventManager';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const handleFocus = (id: string) => {
|
||||
console.log(`窗口 ${id} 获得焦点`);
|
||||
// 更新UI状态,如添加边框高亮
|
||||
};
|
||||
|
||||
const handleClose = (id: string) => {
|
||||
console.log(`窗口 ${id} 已关闭`);
|
||||
// 清理资源,移除DOM节点等
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
wfem.addEventListener('windowFormFocus', handleFocus);
|
||||
wfem.addEventListener('windowFormClose', handleClose);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
wfem.removeEventListener('windowFormFocus', handleFocus);
|
||||
wfem.removeEventListener('windowFormClose', handleClose);
|
||||
});
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
上述代码展示了如何在组件挂载时注册事件监听,并在卸载前正确移除,避免内存泄漏。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L30-L39)
|
||||
|
||||
## 事件解耦带来的低耦合优势
|
||||
采用事件驱动架构后,各组件之间的依赖关系显著降低,具体优势包括:
|
||||
|
||||
- **独立性增强**:组件无需知道谁会发送或接收事件,只需关注自身职责。
|
||||
- **可维护性提升**:修改某一组件不会影响其他不相关的模块。
|
||||
- **扩展性强**:新增功能只需监听已有事件,无需改动现有逻辑。
|
||||
- **测试更简单**:可单独对每个组件进行单元测试,模拟事件输入即可验证行为。
|
||||
|
||||
通过 `wfem` 这一统一事件通道,系统实现了高度模块化的设计,有利于长期迭代和团队协作开发。
|
||||
|
||||
**Section sources**
|
||||
- [IEventBuilder.ts](file://src/events/IEventBuilder.ts#L1-L46)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L1-L95)
|
||||
120
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口还原事件.md
Normal file
120
.qoder/repowiki/zh/content/事件系统/窗口表单事件管理器/窗口还原事件.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# 窗口还原事件
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [核心设计与运行机制](#核心设计与运行机制)
|
||||
3. [事件协同关系分析](#事件协同关系分析)
|
||||
4. [Vue组件中的实践应用](#vue组件中的实践应用)
|
||||
5. [在窗口状态机中的角色](#在窗口状态机中的角色)
|
||||
|
||||
## 简介
|
||||
`windowFormRestore` 事件是桌面应用中用于处理窗口从最大化或最小化状态恢复为正常尺寸的关键事件。该事件通过传递窗口唯一标识符(id)来定位目标窗口实例,并触发相应的UI布局重置逻辑。结合 `windowFormDataUpdate` 事件,可实现窗口位置与尺寸信息的同步更新,确保用户界面状态的一致性。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L22-L22)
|
||||
|
||||
## 核心设计与运行机制
|
||||
`windowFormRestore` 事件定义于 `IWindowFormEvent` 接口中,其函数签名接受一个字符串类型的 `id` 参数,用以标识被操作的窗口实例。当用户点击“还原”按钮或通过快捷键执行还原操作时,系统将调用事件管理器 `wfem` 的 `notifyEvent` 方法,广播该事件。
|
||||
|
||||
事件的实际通知行为由通用事件构建器 `EventBuilderImpl` 实现,它维护了一个基于 `Map` 的监听器集合,支持动态添加、移除和触发事件回调。整个流程具备良好的解耦性和扩展性。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[用户触发窗口还原] --> B[调用 wfem.notifyEvent("windowFormRestore", id)]
|
||||
B --> C{是否存在监听器?}
|
||||
C --> |是| D[遍历执行所有注册的 handler]
|
||||
C --> |否| E[无操作]
|
||||
D --> F[各组件响应还原逻辑]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L22-L22)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L7-L60)
|
||||
- [EventBuilderImpl.ts](file://src/events/impl/EventBuilderImpl.ts#L7-L95)
|
||||
|
||||
## 事件协同关系分析
|
||||
`windowFormRestore` 通常与 `windowFormDataUpdate` 事件协同工作。前者仅通知“还原”动作的发生,而后者负责携带具体的窗口状态数据(包括坐标 x/y 和宽高 width/height),实现精确的状态同步。
|
||||
|
||||
例如,在窗口还原过程中:
|
||||
1. 首先触发 `windowFormRestore(id)`,通知所有监听者窗口即将还原;
|
||||
2. 紧接着发送 `windowFormDataUpdate({ id, state: 'default', x, y, width, height })`,提供新的布局参数;
|
||||
3. UI 组件接收到数据后,更新 DOM 元素的位置与尺寸。
|
||||
|
||||
这种分离设计提高了系统的灵活性和可维护性。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant WM as 窗口管理器
|
||||
participant EM as 事件管理器(wfem)
|
||||
participant UI as UI组件
|
||||
User->>WM : 执行还原操作
|
||||
WM->>EM : notifyEvent("windowFormRestore", id)
|
||||
EM->>UI : 执行所有 windowFormRestore 回调
|
||||
WM->>EM : notifyEvent("windowFormDataUpdate", {id, state, x, y, width, height})
|
||||
EM->>UI : 执行所有 windowFormDataUpdate 回调
|
||||
UI->>UI : 更新DOM样式与位置
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L37-L37)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L5-L9)
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L37-L37)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L5-L9)
|
||||
|
||||
## Vue组件中的实践应用
|
||||
在 Vue 组件中,可通过 `wfem.addEventListener` 监听 `windowFormRestore` 事件,并结合响应式数据重置 UI 布局。建议使用 CSS 过渡动画提升用户体验。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class WindowComponent {
|
||||
+windowId : string
|
||||
+position : WindowFormPos
|
||||
+size : {width : number, height : number}
|
||||
+mounted()
|
||||
+beforeUnmount()
|
||||
}
|
||||
class EventManager {
|
||||
+addEventListener(event, handler)
|
||||
+removeEventListener(event, handler)
|
||||
+notifyEvent(event, ...args)
|
||||
}
|
||||
WindowComponent --> EventManager : 使用 wfem
|
||||
note right of WindowComponent
|
||||
在 mounted 中注册事件监听,
|
||||
在 beforeUnmount 中清理资源
|
||||
end note
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L1-L5)
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L60-L60)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L1-L10)
|
||||
|
||||
## 在窗口状态机中的角色
|
||||
`windowFormRestore` 是窗口状态机中从 `maximized` 或 `minimized` 转换至 `default` 状态的关键触发点。它标志着窗口生命周期中的一个重要转变节点,常伴随以下行为:
|
||||
- 恢复原始位置与尺寸
|
||||
- 重新激活窗口焦点
|
||||
- 触发内容区域重渲染
|
||||
- 更新任务栏图标状态
|
||||
|
||||
该事件与其他窗口控制事件(如 `windowFormMinimize`, `windowFormMaximize`)共同构成了完整的状态转换网络,支撑起复杂的桌面交互体验。
|
||||
|
||||
**Section sources**
|
||||
- [WindowFormEventManager.ts](file://src/events/WindowFormEventManager.ts#L7-L42)
|
||||
- [WindowFormTypes.ts](file://src/ui/types/WindowFormTypes.ts#L5-L9)
|
||||
Reference in New Issue
Block a user