7.5 KiB
7.5 KiB
事件系统设计
设计日期:2025-01-28
设计范围:数据库客户端全局事件系统
状态:设计阶段
一、设计概述
1.1 设计目标
- 简洁统一:所有组件使用统一的事件命名和参数格式
- 易于扩展:新增事件时,遵循统一规范,易于维护
- 类型安全:使用 TypeScript 类型定义,确保类型安全
- 功能强大:支持事件传递、事件拦截、事件日志等高级功能
1.2 设计原则
- 命名规范:事件名称使用 kebab-case,语义清晰
- 参数统一:事件参数使用对象格式,包含必要上下文信息
- 类型定义:所有事件都有明确的 TypeScript 类型定义
- 文档完善:每个事件都有清晰的文档说明
二、事件分类
2.1 连接相关事件
// 连接选择
'connection-select': {
connection: DbConnection
database?: string // 可选,选中的数据库
}
// 连接编辑
'connection-edit': {
connectionId: number
}
// 连接删除
'connection-delete': {
connectionId: number
}
// 连接刷新
'connection-refresh': {
connectionId?: number // 可选,不提供则刷新所有
}
2.2 表结构相关事件
// 查看表结构
'table-structure': {
connectionId: number
database: string
tableName: string // 表名/集合名/Key名
dbType: 'mysql' | 'mongo' | 'redis'
nodeType: 'table' | 'collection' | 'key' | 'database' | 'connection'
}
// 表选择(生成SQL)
'table-select': {
connectionId: number
database: string
tableName: string
sql?: string // 可选,预生成的SQL
}
2.3 SQL执行相关事件
// SQL执行
'sql-execute': {
sql: string
connectionId: number
database?: string
}
// SQL执行完成
'sql-execute-complete': {
result: SqlResult
error?: string
}
2.4 编辑器相关事件
// SQL插入
'sql-insert': {
sql: string
tabKey?: string // 可选,指定Tab
}
// Tab切换
'tab-switch': {
tabKey: string
}
// Tab关闭
'tab-close': {
tabKey: string
}
三、事件系统架构
3.1 事件总线设计
// 事件总线接口
interface EventBus {
// 注册事件监听器
on<T = any>(event: string, handler: (data: T) => void): () => void
// 注册一次性事件监听器
once<T = any>(event: string, handler: (data: T) => void): void
// 移除事件监听器
off(event: string, handler?: Function): void
// 触发事件
emit<T = any>(event: string, data: T): void
// 清除所有监听器
clear(): void
}
// 全局事件总线实例
export const eventBus = createEventBus()
3.2 组件事件映射
// ConnectionTree 组件事件
interface ConnectionTreeEvents {
'connection-select': { connection: DbConnection; database?: string }
'connection-edit': { connectionId: number }
'connection-delete': { connectionId: number }
'table-select': { connectionId: number; database: string; tableName: string }
'table-structure': {
connectionId: number
database: string
tableName: string
dbType: 'mysql' | 'mongo' | 'redis'
nodeType: string
}
'new-connection': void
'show-bookmarks': void
'show-templates': void
}
// SqlEditor 组件事件
interface SqlEditorEvents {
'execute': { sql: string }
'execute-selected': { sql: string }
'sql-insert': { sql: string; tabKey?: string }
'tab-switch': { tabKey: string }
'tab-close': { tabKey: string }
'toggle-editor': void
}
四、事件命名规范
4.1 命名规则
- 格式:
<组件>-<动作>或<功能>-<动作> - 示例:
connection-select:连接选择table-structure:表结构查看sql-execute:SQL执行
4.2 动作词汇表
| 动作 | 说明 | 示例 |
|---|---|---|
| select | 选择 | connection-select |
| edit | 编辑 | connection-edit |
| delete | 删除 | connection-delete |
| create | 创建 | tab-create |
| close | 关闭 | tab-close |
| switch | 切换 | tab-switch |
| execute | 执行 | sql-execute |
| insert | 插入 | sql-insert |
| refresh | 刷新 | connection-refresh |
五、事件参数设计
5.1 参数原则
- 对象格式:所有事件参数使用对象,不使用多个参数
- 必要信息:包含事件处理所需的所有上下文信息
- 可选字段:使用可选字段(
?)标记非必需信息 - 类型明确:所有字段都有明确的类型定义
5.2 参数示例
// ✅ 好的设计:对象格式,类型明确
emit('table-structure', {
connectionId: 1,
database: 'test',
tableName: 'users',
dbType: 'mysql',
nodeType: 'table'
})
// ❌ 不好的设计:多个参数,类型不明确
emit('table-structure', 1, 'test', 'users', 'mysql', 'table')
六、事件处理流程
6.1 事件触发流程
组件内触发事件
↓
emit('event-name', data)
↓
父组件监听事件
↓
调用处理函数
↓
更新状态/执行操作
6.2 事件拦截机制(可选)
// 事件拦截器接口
interface EventInterceptor {
beforeEmit?: (event: string, data: any) => boolean // 返回false阻止事件
afterEmit?: (event: string, data: any) => void // 事件触发后执行
}
// 注册拦截器
eventBus.addInterceptor(interceptor)
七、实现细节
7.1 事件类型定义
// 事件类型定义文件:types/events.ts
export interface ConnectionSelectEvent {
connection: DbConnection
database?: string
}
export interface TableStructureEvent {
connectionId: number
database: string
tableName: string
dbType: 'mysql' | 'mongo' | 'redis'
nodeType: 'table' | 'collection' | 'key' | 'database' | 'connection'
}
// ... 其他事件类型
7.2 组件事件声明
// ConnectionTree.vue
const emit = defineEmits<{
'connection-select': [data: ConnectionSelectEvent]
'table-structure': [data: TableStructureEvent]
'table-select': [data: TableSelectEvent]
// ... 其他事件
}>()
7.3 事件处理
// index.vue
const handleTableStructure = (data: TableStructureEvent) => {
// 加载表结构
structureState.loadStructure(
data.connectionId,
data.database,
data.tableName,
data.dbType
)
// 切换到结构Tab
resultTab.value = 'structure'
}
八、扩展性设计
8.1 事件日志(开发模式)
// 开发模式下记录所有事件
if (import.meta.env.DEV) {
eventBus.on('*', (event, data) => {
console.log(`[Event] ${event}`, data)
})
}
8.2 事件统计(可选)
// 统计事件触发次数
const eventStats = new Map<string, number>()
eventBus.on('*', (event) => {
eventStats.set(event, (eventStats.get(event) || 0) + 1)
})
九、实现优先级
P0(必须实现)
- ✅ 事件类型定义(TypeScript)
- ✅ 连接相关事件
- ✅ 表结构相关事件
- ✅ SQL执行相关事件
P1(重要功能)
- 事件参数验证
- 事件文档完善
- 事件处理错误处理
P2(优化功能)
- 事件拦截机制
- 事件日志(开发模式)
- 事件统计
十、总结
事件系统设计遵循以下原则:
- 简洁统一:统一的事件命名和参数格式
- 类型安全:完整的 TypeScript 类型定义
- 易于扩展:清晰的事件分类和命名规范
- 功能强大:支持事件拦截、日志等高级功能
通过以上设计,可以实现一个简洁、强大、易扩展的事件系统。