Skip to content

Commit 1cb311d

Browse files
张东张东
authored andcommitted
feat: 初始化
1 parent 3ec8c11 commit 1cb311d

File tree

4 files changed

+175
-1
lines changed

4 files changed

+175
-1
lines changed

.vitepress/config.mts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,23 @@ export default defineConfig({
121121
text: "杂项",
122122
link: "/javascript/grammar/misc",
123123
},
124+
{
125+
text: "冒泡与捕获",
126+
link: "/javascript/grammar/bubbling",
127+
},
124128
],
125129
},
126130
],
131+
"/frame/react/": [
132+
{
133+
text: "开始",
134+
link: "/frame/react/start",
135+
},
136+
{
137+
text: "state",
138+
link: "/frame/react/state",
139+
},
140+
],
127141
"/Web-Api/": [
128142
{
129143
text: "Web-Api",

frame/react/start.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,23 @@ function Profile() {
145145
}
146146
```
147147
当子组件需要来自父组件的一些数据时,通过 props 传递它,而不是嵌套定义。
148-
:::
148+
:::
149+
150+
151+
## onClickCapture
152+
极少数情况下,你可能需要捕获子元素上的所有事件,即便它们阻止了传播。例如,你可能想对每次点击进行埋点记录,传播逻辑暂且不论。那么你可以通过在事件名称末尾添加 Capture 来实现这一点:
153+
```js
154+
<div onClickCapture={() => { /* 这会首先执行 */ }}>
155+
<button onClick={e => e.stopPropagation()} />
156+
<button onClick={e => e.stopPropagation()} />
157+
</div>
158+
```
159+
每个事件分三个阶段传播:
160+
161+
1. 它向下传播,调用所有的 onClickCapture 处理函数。
162+
2. 它执行被点击元素的 onClick 处理函数。
163+
3. 它向上传播,调用所有的 onClick 处理函数。
164+
165+
捕获事件对于路由或数据分析之类的代码很有用,但你可能不会在应用程序代码中使用它们。
166+
167+
这就相当监听元素的捕获事件

frame/react/state.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
outline: deep
3+
layout: doc
4+
---
5+
6+
```jsx
7+
function example(){
8+
let count = 0
9+
function handleClick(){
10+
++count
11+
}
12+
return (<>
13+
<div>{count}</div>
14+
<button onClick={handleClick}>add</button>
15+
</>
16+
)
17+
}
18+
```
19+
20+
不会有任何变化
21+
22+
handleClick() 事件处理函数正在更新局部变量 count
23+
24+
* 更新局部变量react不会触发渲染, React 没有意识到它需要使用新数据再次渲染组件。
25+
* 就算react重新渲染,再次执行这个函数,之前修改的局部变量修改已经丢失,渲染的结果都是一样的
26+
27+
要使用新数据更新组件,需要做两件事:
28+
29+
* 保留 渲染之间的数据。
30+
* 触发 React 使用新数据渲染组件(重新渲染)。
31+
32+
useState Hook 提供了这两个功能:
33+
34+
* State 变量 用于保存渲染间的数据。
35+
* State setter 函数 更新变量并触发 React 再次渲染组件。
36+
## useState
37+
```js
38+
const [index, setIndex] = useState(0);
39+
```
40+
41+
1. 组件进行第一次渲染。 因为你将 0 作为 index 的初始值传递给 useState,它将返回 [0, setIndex]。 React 记住 0 是最新的 state 值。
42+
2. 你更新了 state。当用户点击按钮时,它会调用 setIndex(index + 1)。 index 是 0,所以它是 setIndex(1)。这告诉 React 现在记住 index 是 1 并触发下一次渲染。
43+
3. 组件进行第二次渲染。React 仍然看到 useState(0),但是因为 React 记住 了你将 index 设置为了 1,它将返回 [1, setIndex]
44+
4. 以此类推!
45+
46+
<iframe src="https://codesandbox.io/embed/magical-meitner-hcs52m?fontsize=14&hidenavigation=1&theme=dark"
47+
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
48+
title="magical-meitner-hcs52m"
49+
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
50+
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
51+
></iframe>
52+
53+
:::tip :thinking:
54+
Hooks ——以 use 开头的函数——只能在组件或自定义 Hook 的最顶层调用。 你不能在条件语句、循环语句或其他嵌套函数内调用 Hook。
55+
:::

javascript/grammar/bubbling.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
outline: deep
3+
layout: doc
4+
---
5+
6+
## 冒泡
7+
**当一个事件发生在一个元素上,它会首先运行在该元素上的处理程序,然后运行其父元素上的处理程序,然后一直向上到其他祖先上的处理程序。**
8+
9+
:::tip :rocket: 几乎所有事件都会冒泡。
10+
这句话中的关键词是“几乎”。
11+
12+
例如,focus 事件不会冒泡。同样,我们以后还会遇到其他例子。但这仍然是例外,而不是规则,大多数事件的确都是冒泡的。
13+
:::
14+
## event target
15+
父元素上的处理程序始终可以获取事件实际发生位置的详细信息。
16+
17+
**引发事件的那个嵌套层级最深的元素被称为目标元素,可以通过 event.target 访问。**
18+
19+
注意与 this(=event.currentTarget)之间的区别:
20+
21+
* event.target —— 是引发事件的“目标”元素,它在冒泡过程中不会发生变化。
22+
* this —— 是“当前”元素,其中有一个当前正在运行的处理程序。
23+
24+
因此,event.target 可能会等于 this
25+
## 停止冒泡
26+
```js
27+
event.stopPropagation()
28+
```
29+
30+
:::tip :rocket:event.stopImmediatePropagation()
31+
如果一个元素在一个事件上有多个处理程序,即使其中一个停止冒泡,其他处理程序仍会执行。
32+
33+
换句话说,event.stopPropagation() 停止向上移动,但是当前元素上的其他处理程序都会继续运行。
34+
35+
有一个 event.stopImmediatePropagation() 方法,可以用于停止冒泡,并阻止当前元素上的处理程序运行。使用该方法之后,其他处理程序就不会被执行。
36+
```js
37+
button.addEventListener('click', (event) => {
38+
event.stopImmediatePropagation(); // 阻止事件冒泡和当前元素上的其他事件处理程序
39+
alert('按钮点击事件1');
40+
});
41+
42+
button.addEventListener('click', () => {
43+
alert('按钮点击事件2'); // 不会触发
44+
});
45+
46+
document.addEventListener('click', () => {
47+
alert('文档点击事件'); // 不会触发
48+
});
49+
```
50+
:::
51+
52+
## 捕获
53+
事件处理的另一个阶段被称为“捕获(capturing)”。它很少被用在实际开发中,但有时是有用的。
54+
55+
DOM 事件标准描述了事件传播的 3 个阶段:
56+
57+
1. 捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
58+
2. 目标阶段(Target phase)—— 事件到达目标元素。
59+
3. 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡。
60+
61+
![alt text](https://zh.javascript.info/article/bubbling-and-capturing/eventflow.svg)
62+
63+
也就是说:点击 `<td>`,事件首先通过祖先链向下到达元素(捕获阶段),然后到达目标(目标阶段),最后上升(冒泡阶段),*在途中调用处理程序*
64+
65+
之前,我们只讨论了冒泡,因为捕获阶段很少被使用。通常我们看不到它。
66+
67+
使用 `on<event>` 属性或使用 HTML 特性(attribute)或使用两个参数的 addEventListener(event, handler) 添加的处理程序,对捕获一无所知,它们仅在第二阶段和第三阶段运行。
68+
69+
为了在捕获阶段捕获事件,我们需要将处理程序的 capture 选项设置为 true:
70+
```js
71+
elem.addEventListener(..., {capture: true})
72+
// 或者,用 {capture: true} 的别名 "true"
73+
elem.addEventListener(..., true)
74+
```
75+
capture 选项有两个可能的值:
76+
77+
* 如果为 false(默认值),则在冒泡阶段设置处理程序。
78+
* 如果为 true,则在捕获阶段设置处理程序。
79+
80+
请注意,虽然形式上有 3 个阶段,但第 2 阶段(“目标阶段”:事件到达元素)没有被单独处理:捕获阶段和冒泡阶段的处理程序都在该阶段被触发。
81+
82+
:::warning :warning: 要移除处理程序,removeEventListener 需要同一阶段
83+
如果我们 addEventListener(..., true),那么我们应该在 removeEventListener(..., true) 中提到同一阶段,以正确删除处理程序。
84+
:::
85+
86+
还可以通过event.eventPhase —— 获取当前阶段(capturing=1,target=2,bubbling=3)。

0 commit comments

Comments
 (0)