SyntheticEvent
This commit is contained in:
parent
ad3fe496ef
commit
dd9f5dcaaa
90
demo/test-event/event.js
Normal file
90
demo/test-event/event.js
Normal file
@ -0,0 +1,90 @@
|
||||
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();
|
||||
});
|
22
demo/test-event/index.html
Normal file
22
demo/test-event/index.html
Normal file
@ -0,0 +1,22 @@
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
</head>
|
||||
<div id="root">
|
||||
<div>1</div>
|
||||
<div>
|
||||
222
|
||||
<div>222-child</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app">
|
||||
<button class="button">Click Me</button>
|
||||
<a href="#" class="link">Link</a>
|
||||
<div id="i2">
|
||||
222
|
||||
<div id="i2-child">222-child</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <script src="./index.js"></script> -->
|
||||
<script src="./event.js"></script>
|
69
demo/test-event/index.js
Normal file
69
demo/test-event/index.js
Normal file
@ -0,0 +1,69 @@
|
||||
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(); // 停止冒泡,防止触发父级模块
|
||||
});
|
13
demo/test-event/package.json
Normal file
13
demo/test-event/package.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "test-event",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
||||
"license": "MIT",
|
||||
"type": "module"
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="a-[123]">sdfsdf</div>
|
||||
<script src="./src/main.tsx" type="module"></script>
|
||||
</body>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user