70 lines
2.2 KiB
JavaScript
70 lines
2.2 KiB
JavaScript
const root = document.getElementById('root');
|
||
|
||
// 全局事件管理对象
|
||
const eventRegistry = [];
|
||
|
||
// 注册事件方法
|
||
function delegateEvent(selector, callback) {
|
||
const newEntry = { selector, callback };
|
||
|
||
// 获取新选择器对应的元素
|
||
const newElement = document.querySelector(selector);
|
||
if (!newElement) return; // 如果选择器无效,直接返回
|
||
|
||
// 动态插入到 eventRegistry,并根据包含关系排序
|
||
let inserted = false;
|
||
for (let i = 0; i < eventRegistry.length; i++) {
|
||
const existingElement = document.querySelector(eventRegistry[i].selector);
|
||
if (existingElement && existingElement.contains(newElement)) {
|
||
// 当前选择器包含新选择器,新选择器应该插在当前选择器后面
|
||
eventRegistry.splice(i + 1, 0, newEntry);
|
||
inserted = true;
|
||
break;
|
||
} else if (newElement.contains(existingElement)) {
|
||
// 新选择器包含当前选择器,新选择器应该插在当前选择器前面
|
||
eventRegistry.splice(i, 0, newEntry);
|
||
inserted = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 如果没有找到合适的位置,直接追加到末尾
|
||
if (!inserted) {
|
||
eventRegistry.push(newEntry);
|
||
}
|
||
}
|
||
|
||
// 为 Event 添加一个标志来记录是否已停止冒泡
|
||
(function () {
|
||
const originalStopPropagation = Event.prototype.stopPropagation;
|
||
Event.prototype.stopPropagation = function () {
|
||
this.propagationStopped = true;
|
||
originalStopPropagation.call(this); // 调用原始的 stopPropagation 方法
|
||
};
|
||
})();
|
||
|
||
// 统一事件处理函数
|
||
root.addEventListener('click', (event) => {
|
||
const target = event.target;
|
||
|
||
// 遍历排序后的注册表
|
||
for (const { selector, callback } of eventRegistry.reverse()) {
|
||
if (event.propagationStopped) break; // 停止冒泡时中断匹配
|
||
|
||
const element = document.querySelector(selector);
|
||
if (element && (element === target || element.contains(target))) {
|
||
callback(event);
|
||
}
|
||
}
|
||
});
|
||
|
||
// 示例:为 `222-child` 和 `222` 添加点击事件
|
||
delegateEvent('#root > div:nth-child(2)', (event) => {
|
||
console.log('222 被点击');
|
||
});
|
||
|
||
delegateEvent('#root > div:nth-child(2) > div', (event) => {
|
||
console.log('222-child 被点击');
|
||
event.stopPropagation(); // 停止冒泡,防止触发父级模块
|
||
});
|