91 lines
2.4 KiB
JavaScript
91 lines
2.4 KiB
JavaScript
class SyntheticEvent {
|
|
constructor(nativeEvent) {
|
|
this.nativeEvent = nativeEvent;
|
|
this.target = nativeEvent.target;
|
|
this.currentTarget = null;
|
|
this.defaultPrevented = false;
|
|
this.propagationStopped = false; // 添加冒泡停止标志
|
|
}
|
|
|
|
preventDefault() {
|
|
this.nativeEvent.preventDefault();
|
|
this.defaultPrevented = true;
|
|
}
|
|
|
|
stopPropagation() {
|
|
this.propagationStopped = true; // 标记 SyntheticEvent 冒泡停止
|
|
}
|
|
}
|
|
|
|
class EventSystem {
|
|
constructor(root) {
|
|
this.root = root;
|
|
this.handlers = {};
|
|
}
|
|
|
|
on(type, selector, handler) {
|
|
if (!this.handlers[type]) {
|
|
this.handlers[type] = [];
|
|
// 绑定到根元素
|
|
this.root.addEventListener(type, (event) => this.dispatch(event, type));
|
|
}
|
|
this.handlers[type].push({ selector, handler });
|
|
}
|
|
|
|
dispatch(nativeEvent, type) {
|
|
const syntheticEvent = new SyntheticEvent(nativeEvent);
|
|
let target = nativeEvent.target;
|
|
|
|
// 模拟冒泡过程
|
|
while (target && target !== this.root) {
|
|
if (syntheticEvent.propagationStopped) {
|
|
break; // 如果已停止冒泡,则退出
|
|
}
|
|
|
|
this.handlers[type]?.forEach(({ selector, handler }) => {
|
|
if (target.matches(selector)) {
|
|
syntheticEvent.currentTarget = target; // 当前目标元素
|
|
handler(syntheticEvent);
|
|
|
|
if (syntheticEvent.propagationStopped) {
|
|
return; // 停止事件的进一步处理
|
|
}
|
|
}
|
|
});
|
|
|
|
target = target.parentElement; // 向父节点继续冒泡
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取根节点
|
|
const root = document.getElementById('app');
|
|
|
|
// 创建事件系统
|
|
const eventSystem = new EventSystem(root);
|
|
|
|
// 注册事件
|
|
eventSystem.on('click', '.button', (event) => {
|
|
console.log('Button clicked:', event.currentTarget.innerText);
|
|
event.preventDefault();
|
|
});
|
|
|
|
eventSystem.on('click', '.link', (event) => {
|
|
console.log('Link clicked:', event.currentTarget.href);
|
|
// event.stopPropagation();
|
|
// event.preventDefault();
|
|
});
|
|
|
|
eventSystem.on('click', '#i2', (event) => {
|
|
// console.log('i2 clicked:', event.currentTarget.innerText);
|
|
console.log('i2 clicked:', event.currentTarget);
|
|
// event.preventDefault();
|
|
});
|
|
|
|
eventSystem.on('click', '#i2-child', (event) => {
|
|
// console.log('i2-child clicked:', event.currentTarget.innerText);
|
|
console.log('i2-child clicked:', event.currentTarget);
|
|
// event.preventDefault();
|
|
event.stopPropagation();
|
|
});
|