所有事件处理必须通过 EventManager 进行统一管理。这是 ZerOS 系统的强制要求。
EventManager.registerEventHandler() 注册全局事件EventManager.registerElementEvent() 注册元素特定事件(如 mouseenter, mouseleave, load, error)addEventListener(会被警告,不推荐)原因:
EventManager 是 ZerOS 内核的事件管理器,统一管理所有事件处理。它提供了:
KernelLogger - 内核日志系统(用于日志输出)PermissionManager - 权限管理系统(用于权限检查)ProcessManager - 进程管理系统(用于获取当前 PID)事件管理器在首次使用时自动初始化:
EventManager.init();
registerEventHandler(pid, eventType, handler, options)注册事件处理程序。这是事件管理器的核心API,所有事件处理都应该通过此API注册。
参数:
pid (number): 程序PIDeventType (string): 事件类型(如 'click', 'contextmenu', 'keydown', 'mousedown' 等)handler (Function): 事件处理函数 (event, eventContext) => { ... }
event: 原生事件对象eventContext: 事件上下文对象,提供以下方法:
eventContext.stopPropagation(): 停止事件传播eventContext.stopImmediatePropagation(): 立即停止事件传播eventContext.preventDefault(): 阻止默认行为eventContext.stopped: 是否已停止传播(只读)eventContext.prevented: 是否已阻止默认行为(只读)eventContext.currentHandler: 当前处理程序信息(只读)false: 阻止默认行为'stop' 或 'stopPropagation': 停止事件传播'stopImmediate' 或 'stopImmediatePropagation': 立即停止事件传播options (Object): 选项对象
priority (number): 优先级(数字越小优先级越高,默认100)selector (string): CSS选择器(可选,只在匹配的元素上触发)stopPropagation (boolean): 是否阻止事件传播(默认false)once (boolean): 是否只触发一次(默认false)passive (boolean): 是否被动监听(默认false)useCapture (boolean): 是否使用捕获阶段(默认false)返回: number - 处理程序ID,用于注销
权限要求: 需要 PermissionManager.PERMISSION.EVENT_LISTENER 权限
示例:
// 基本用法
const handlerId = EventManager.registerEventHandler(pid, 'click', (e) => {
console.log('点击事件', e.target);
});
// 使用优先级和选择器
const handlerId2 = EventManager.registerEventHandler(pid, 'click', (e) => {
console.log('按钮点击', e.target);
}, {
priority: 50, // 高优先级
selector: '.my-button' // 只在 .my-button 元素上触发
});
// 使用事件上下文控制传播
const handlerId3 = EventManager.registerEventHandler(pid, 'click', (e, ctx) => {
// 阻止事件传播
ctx.stopPropagation();
// 或返回 'stop' 来停止传播
return 'stop';
}, {
priority: 10 // 最高优先级
});
// 只触发一次
const handlerId4 = EventManager.registerEventHandler(pid, 'keydown', (e) => {
console.log('按键:', e.key);
}, {
once: true
});
unregisterEventHandler(handlerId)注销事件处理程序。
参数:
handlerId (number): 处理程序ID(由 registerEventHandler 返回)示例:
const handlerId = EventManager.registerEventHandler(pid, 'click', handler);
// ... 使用后注销
EventManager.unregisterEventHandler(handlerId);
unregisterAllHandlersForPid(pid)注销程序的所有事件处理程序。通常不需要手动调用,ProcessManager 会在程序退出时自动调用。
参数:
pid (number): 程序PID注意: 此方法会自动清理通过 registerEventHandler 和 registerElementEvent 注册的所有事件处理程序。
示例:
// 通常不需要手动调用,ProcessManager 会自动清理
// 但如果需要提前清理,可以手动调用:
EventManager.unregisterAllHandlersForPid(this.pid);
registerElementEvent(pid, element, eventType, handler, options)注册元素特定的事件(不会冒泡的事件,如 mouseenter, mouseleave, load, error)。这些事件需要直接绑定到元素上,但通过 EventManager 统一管理。
参数:
pid (number): 程序PIDelement (HTMLElement): 元素对象eventType (string): 事件类型(如 'mouseenter', 'mouseleave', 'load', 'error')handler (Function): 事件处理函数 (event, eventContext) => { ... }
event: 原生事件对象eventContext: 事件上下文对象(可选,提供 stopPropagation 等方法)options (Object): 选项对象(可选)
once (boolean): 是否只触发一次(默认false)passive (boolean): 是否被动监听(默认false)返回: number - 处理程序ID,用于注销
权限要求: 需要 PermissionManager.PERMISSION.EVENT_LISTENER 权限
示例:
// 注册 mouseenter 事件(不会冒泡)
const handlerId = EventManager.registerElementEvent(
this.pid,
buttonElement,
'mouseenter',
(e) => {
buttonElement.style.backgroundColor = 'blue';
}
);
// 注册 load 事件
const loadHandlerId = EventManager.registerElementEvent(
this.pid,
imageElement,
'load',
(e) => {
console.log('图片加载完成');
},
{ once: true } // 只触发一次
);
// 注册 error 事件
const errorHandlerId = EventManager.registerElementEvent(
this.pid,
imageElement,
'error',
(e) => {
console.error('图片加载失败');
}
);
unregisterElementEvent(handlerId)注销元素特定的事件。
参数:
handlerId (number): 处理程序ID(由 registerElementEvent 返回)示例:
const handlerId = EventManager.registerElementEvent(pid, element, 'mouseenter', handler);
// ... 使用后注销
EventManager.unregisterElementEvent(handlerId);
注意: 程序退出时,ProcessManager 会自动调用 unregisterAllHandlersForPid 清理所有事件处理程序,包括元素特定事件。
stopPropagation(event, eventContext)阻止事件传播。
参数:
event (Event): 事件对象eventContext (Object): 事件上下文对象(可选,如果提供则使用上下文)示例:
EventManager.registerEventHandler(pid, 'click', (e, ctx) => {
EventManager.stopPropagation(e, ctx);
});
stopImmediatePropagation(event, eventContext)立即阻止事件传播。
参数:
event (Event): 事件对象eventContext (Object): 事件上下文对象(可选)示例:
EventManager.registerEventHandler(pid, 'click', (e, ctx) => {
EventManager.stopImmediatePropagation(e, ctx);
});
preventDefault(event, eventContext)阻止默认行为。
参数:
event (Event): 事件对象eventContext (Object): 事件上下文对象(可选)示例:
EventManager.registerEventHandler(pid, 'contextmenu', (e, ctx) => {
EventManager.preventDefault(e, ctx);
});
registerMenu(menuId, menu, closeCallback, excludeSelectors)注册一个菜单,当点击外部时自动关闭。
参数:
menuId (string): 菜单唯一标识menu (HTMLElement): 菜单元素closeCallback (Function): 关闭回调函数excludeSelectors (Array示例:
const menu = document.querySelector('.context-menu');
EventManager.registerMenu('my-menu', menu, () => {
menu.classList.remove('visible');
}, ['.menu-trigger']);
unregisterMenu(menuId)注销一个菜单。
参数:
menuId (string): 菜单唯一标识示例:
EventManager.unregisterMenu('my-menu');
registerDrag(windowId, element, window, state, onDragStart, onDrag, onDragEnd, excludeSelectors)注册窗口拖动。
参数:
windowId (string): 窗口唯一标识element (HTMLElement): 可拖动元素(通常是窗口标题栏)window (HTMLElement): 窗口元素state (Object): 状态对象(用于存储拖动状态)onDragStart (Function): 拖动开始回调 (e) => {}onDrag (Function): 拖动中回调 (e) => {}onDragEnd (Function): 拖动结束回调 (e) => {}excludeSelectors (Array示例:
const state = { isDragging: false, startX: 0, startY: 0 };
EventManager.registerDrag(
'window-1',
titleBar,
windowElement,
state,
(e) => {
state.isDragging = true;
state.startX = e.clientX - windowElement.offsetLeft;
state.startY = e.clientY - windowElement.offsetTop;
},
(e) => {
if (state.isDragging) {
windowElement.style.left = (e.clientX - state.startX) + 'px';
windowElement.style.top = (e.clientY - state.startY) + 'px';
}
},
(e) => {
state.isDragging = false;
}
);
unregisterDrag(windowId)注销窗口拖动。
参数:
windowId (string): 窗口唯一标识示例:
EventManager.unregisterDrag('window-1');
registerResizer(resizerId, resizerElement, window, state, onResizeStart, onResize, onResizeEnd)注册窗口拉伸。
参数:
resizerId (string): 拉伸器唯一标识resizerElement (HTMLElement): 拉伸元素(通常是窗口边缘)window (HTMLElement): 窗口元素state (Object): 状态对象(用于存储拉伸状态)onResizeStart (Function): 拉伸开始回调 (e) => {}onResize (Function): 拉伸中回调 (e) => {}onResizeEnd (Function): 拉伸结束回调 (e) => {}示例:
const state = { isResizing: false, startX: 0, startY: 0, startWidth: 0, startHeight: 0 };
EventManager.registerResizer(
'resizer-1',
resizerElement,
windowElement,
state,
(e) => {
state.isResizing = true;
state.startX = e.clientX;
state.startY = e.clientY;
state.startWidth = windowElement.offsetWidth;
state.startHeight = windowElement.offsetHeight;
},
(e) => {
if (state.isResizing) {
const deltaX = e.clientX - state.startX;
const deltaY = e.clientY - state.startY;
windowElement.style.width = (state.startWidth + deltaX) + 'px';
windowElement.style.height = (state.startHeight + deltaY) + 'px';
}
},
(e) => {
state.isResizing = false;
}
);
unregisterResizer(resizerId)注销窗口拉伸。
参数:
resizerId (string): 拉伸器唯一标识示例:
EventManager.unregisterResizer('resizer-1');
registerSelector(selectorId, iconElement, selectorElement, onShow, onHide, onClickOutside, showDelay, hideDelay)注册多任务选择器(任务栏程序图标悬停显示)。
参数:
selectorId (string): 选择器唯一标识iconElement (HTMLElement): 图标元素(触发元素)selectorElement (HTMLElement): 选择器元素(显示的元素)onShow (Function): 显示回调 () => {}onHide (Function): 隐藏回调 () => {}onClickOutside (Function): 点击外部回调 () => {}(可选)showDelay (number): 显示延迟(毫秒,默认 300)hideDelay (number): 隐藏延迟(毫秒,默认 200)示例:
EventManager.registerSelector(
'selector-1',
iconElement,
selectorElement,
() => {
selectorElement.style.display = 'block';
},
() => {
selectorElement.style.display = 'none';
},
null,
300,
200
);
unregisterSelector(selectorId)注销多任务选择器。
参数:
selectorId (string): 选择器唯一标识示例:
EventManager.unregisterSelector('selector-1');
// 创建上下文菜单
const contextMenu = document.createElement('div');
contextMenu.className = 'context-menu';
contextMenu.innerHTML = `
<div class="menu-item">复制</div>
<div class="menu-item">粘贴</div>
<div class="menu-item">删除</div>
`;
document.body.appendChild(contextMenu);
// 注册菜单
EventManager.registerMenu('context-menu', contextMenu, () => {
contextMenu.classList.remove('visible');
}, ['.menu-trigger']);
// 显示菜单
function showContextMenu(x, y) {
contextMenu.style.left = x + 'px';
contextMenu.style.top = y + 'px';
contextMenu.classList.add('visible');
}
// 程序退出时注销
__exit__: function() {
EventManager.unregisterMenu('context-menu');
}
// 在窗口创建时注册拖动
function createWindow(pid, title) {
const window = document.createElement('div');
window.className = 'window';
const titleBar = document.createElement('div');
titleBar.className = 'window-title-bar';
titleBar.textContent = title;
window.appendChild(titleBar);
const state = { isDragging: false, startX: 0, startY: 0 };
EventManager.registerDrag(
`window-${pid}`,
titleBar,
window,
state,
(e) => {
state.isDragging = true;
state.startX = e.clientX - window.offsetLeft;
state.startY = e.clientY - window.offsetTop;
},
(e) => {
if (state.isDragging) {
window.style.left = (e.clientX - state.startX) + 'px';
window.style.top = (e.clientY - state.startY) + 'px';
}
},
(e) => {
state.isDragging = false;
}
);
return window;
}
// 窗口关闭时注销
function closeWindow(pid) {
EventManager.unregisterDrag(`window-${pid}`);
}
// 注册窗口拉伸
function registerWindowResize(window, resizerElement) {
const state = { isResizing: false, startX: 0, startY: 0, startWidth: 0, startHeight: 0 };
EventManager.registerResizer(
`resizer-${window.id}`,
resizerElement,
window,
state,
(e) => {
state.isResizing = true;
state.startX = e.clientX;
state.startY = e.clientY;
state.startWidth = window.offsetWidth;
state.startHeight = window.offsetHeight;
},
(e) => {
if (state.isResizing) {
const deltaX = e.clientX - state.startX;
const deltaY = e.clientY - state.startY;
window.style.width = (state.startWidth + deltaX) + 'px';
window.style.height = (state.startHeight + deltaY) + 'px';
}
},
(e) => {
state.isResizing = false;
}
);
}
事件管理器按照优先级顺序执行处理程序(数字越小优先级越高):
事件管理器提供了多种方式来控制事件传播:
stopPropagation: true'stop' 或 'stopImmediate'eventContext.stopPropagation()EventManager.stopPropagation(e, ctx)EventManager 会拦截 document.addEventListener、window.addEventListener 和 Element.prototype.addEventListener 调用:
addEventListener,不会记录警告addEventListener,但会记录警告日志,建议使用 EventManager APIaddEventListener,但会记录警告日志警告信息示例:
[内核][EventManager] [警告] 程序 (PID: 10002) 直接使用 document.addEventListener 注册事件 "click"。
建议使用 EventManager.registerEventHandler() 进行统一管理,以便支持事件优先级、传播控制和自动清理。
为什么建议使用 EventManager:
EVENT_LISTENER 权限(在 __info__ 中声明)ProcessManager 会自动调用 unregisterAllHandlersForPid 清理事件处理程序useCapture 选项控制selector 选项可以限制事件只在匹配的元素上触发mouseenter, mouseleave, load, error),使用 registerElementEvent 方法addEventListener 会被警告,建议迁移到 EventManager APIgetStats()获取事件统计信息(用于调试)。
返回: Object - 统计信息对象
示例:
const stats = EventManager.getStats();
console.log('事件类型数:', stats.totalEventTypes);
console.log('处理程序总数:', stats.totalHandlers);
console.log('按事件类型分组:', stats.handlersByEventType);
console.log('按PID分组:', stats.handlersByPid);
getHandlersForEvent(eventType)获取指定事件类型的所有处理程序信息(用于调试)。
参数:
eventType (string): 事件类型返回: Array - 处理程序信息数组
示例:
const handlers = EventManager.getHandlersForEvent('click');
console.log('click事件的处理程序:', handlers);