2025-05-16 日报 Day188

2025-05-16 日报 Day188

Yuyang 前端小白🥬

今日的鸡汤

勇者逆行,令人惊叹的中国速度背后,是一名名建设者日夜兼程的无怨劳作。

今日学习内容

1、https://www.youtube.com/watch?v=EVFZazcxAbo&t=4112s

今日笔记

React事件与原生DOM事件的区别
事件工作流、事件特征等逻辑层面问题的理解

回顾原生DOM下的事件流:

一个页面往往会被绑定许许多多的事件,而页面接受事件的顺序,就是事件流。

image-20250708212701831

事件委托:把多个子元素的同一类型的监听逻辑合并到父元素上通过一个监听函数来管理的行为

当事件在具体的DOM节点上被触发后,最终都会冒泡到document上,document上所绑定的统一事件处理程序会将事件分发到具体的组件实例。

React合成事件
在底层抹了不同浏览器的差异
在上层面向开发者暴露统一的、稳定的、与DOM原生事件相同的事件接口
虽然合成事件并不是原生DOM事件,但它保存里原生DOM事件的引用

React事件系统工作流拆解:
事件绑定:事件的绑定是在completeWork中完成的
completeWork内部有三个关键动作:
创建DOM节点(createInstance)
将DOM节点插入到DOM树中(appendAllChildren)
为DOM节点设置属性(finalizeInitialChildren)

image-20250708215454780

image-20250708215519084

image-20250708215532024

React最终注册到document上并不是某一个DOM节点上对应的具体回调逻辑而是一个统一的事件分发函数

linstner
最后绑定到document上的这个统一的事件分发函数其实就是dispatchEvent

事件触发的本质就是对dispatchEvent函数的调用

image-20250708220122754

事件回调的收集与执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from 'react';
import { useState } from 'react';
function App(){
const [state, setState] = useState(0);

return(
<div className="App">
<div id="container" onClickCapture={()=>console.log("捕获经过div")}
onClick={()=>console.log("冒泡经过div")}
className="container"
>
<p style={{width: 128, textAlign: 'center'}}>
{state}
</p>
<button style={{width: 128}} onClick={()=>{
setState(state+1)}}>点击+1</button>
</div>
</div>
)
}

![image-20250708221023052](../../../../../Library/Application Support/typora-user-images/image-20250708221023052.png)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function traverseTwoPhase(inst,fn,arg){
// 定义一个path数组
var path=[];

while(inst){
// 将当前节点收集进path数组
path.push(inst);
// 向上收集tag===HostComponent的父节点
inst=getParent(inst);
}

var i;

// 从后往前,收集path数组中会参与捕获过程的节点与对应回调
for(i=path.length;i-->0;){
fn(path[i],'captured',arg);
}

// 从前往后,收集path数组中会参与冒泡过程的节点与对应回调
for(i=0;i<path.length;i++){
fn(path[i],'bubbled',arg);
}
}

循环收集符合条件的父节点,存进path数组中
traverseTwoPhase会以当前节点(触发事件的目标节点)为起点不断向上寻找tag===HostComponent的父节点并将这些节点按顺序收集进path数组中

HostComponent是DOM元素对应的Fiber节点类型此处限制tag===HostComponent也就是说只收集DOM元素对应的Fiber节点

image-20250708235047831

模拟事件在捕获阶段的传播顺序,收集捕获阶段相关的节点实例与回调函数
path数组中子节点在前,祖先节点在后
其实就是从父节点往下遍历子节点直至遍历到目标节点的过程这个遍历顺序和事件在捕获阶段的传播顺序一致

模拟事件在冒泡阶段的传播顺序,收集冒泡阶段相关的节点实例与回调函数
唯一的区别是对path数组的倒序遍历变成啦正序遍历

正序遍历自然模拟的就是冒泡阶段的事件传播顺序
若该节点上对应当前事件的冒泡回调不为空
那么节点实例和事件回调同样会分别被收集到SyntheticEvent._dispatchInstances和SyntheticEvent._dispatchListeners中去

image-20250709002044929

此页目录
2025-05-16 日报 Day188