-
zhangwei
2026-04-08 ef5050890cf37409628df47e9c820ac345434209
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue3响应式系统原理 · 宋体五号示意图</title>
    <style>
        /* 全局字体设置:宋体五号 (五号 ≈ 10.5pt ≈ 14px,为屏幕清晰稍调) */
        body {
            font-family: 'SimSun', '宋体', 'Songti SC', STSong, 'Times New Roman', serif;
            font-size: 14px;          /* 五号约10.5pt,对应14px清晰 */
            line-height: 1.5;
            background: #f5f7fa;
            margin: 0;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
            box-sizing: border-box;
        }
        .diagram-container {
            max-width: 1000px;
            width: 100%;
            background: white;
            box-shadow: 0 8px 20px rgba(0,0,0,0.1);
            border-radius: 16px;
            padding: 24px 20px 30px 20px;
            border: 1px solid #e2e8f0;
        }
        /* 主标题 */
        .title {
            text-align: center;
            font-size: 20px;
            font-weight: 600;
            margin-bottom: 16px;
            color: #2c3e50;
            letter-spacing: 1px;
            border-bottom: 2px solid #42b883;
            padding-bottom: 10px;
        }
        /* 副标题/区域标识 */
        .section-label {
            font-weight: 600;
            color: #2c3e50;
            background: #edf2f7;
            display: inline-block;
            padding: 4px 14px;
            border-radius: 30px;
            font-size: 14px;
            margin-bottom: 12px;
            border-left: 4px solid #42b883;
        }
        /* 三列布局: 左侧优势 + 核心流程 + 右侧ref */
        .main-panel {
            display: flex;
            gap: 16px;
            margin-top: 10px;
            flex-wrap: wrap;
        }
        .left-panel {
            flex: 1.2;
            min-width: 220px;
            background: #f8fafc;
            border-radius: 16px;
            padding: 16px 14px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.03);
            border: 1px solid #e9eef3;
        }
        .center-panel {
            flex: 2.2;
            min-width: 380px;
            background: #f8fafc;
            border-radius: 16px;
            padding: 16px 14px;
            border: 1px solid #e9eef3;
            box-shadow: 0 2px 8px rgba(0,0,0,0.03);
        }
        .right-panel {
            flex: 1;
            min-width: 210px;
            background: #f8fafc;
            border-radius: 16px;
            padding: 16px 14px;
            border: 1px solid #e9eef3;
            box-shadow: 0 2px 8px rgba(0,0,0,0.03);
        }
        /* 引用标记小字 */
        .ref-note {
            color: #64748b;
            font-size: 12px;   /* 稍小但仍保持宋体 */
            margin-top: 8px;
            border-top: 1px dashed #cbd5e1;
            padding-top: 8px;
        }
        /* 流程图卡片样式 */
        .flow-step {
            background: white;
            border-radius: 12px;
            padding: 12px 10px;
            margin-bottom: 12px;
            border-left: 5px solid #42b883;
            box-shadow: 0 2px 6px rgba(0,0,0,0.02);
            border: 1px solid #dde7f0;
            border-left-width: 5px;
            border-left-color: #42b883;
            position: relative;
        }
        .flow-step strong {
            color: #1e293b;
            font-weight: 600;
            display: block;
            margin-bottom: 5px;
            font-size: 14.5px;
        }
        .flow-step .desc {
            color: #334155;
            margin-left: 6px;
        }
        /* 箭头连线示意 (简单用字符) */
        .arrow-down {
            text-align: center;
            color: #94a3b8;
            font-size: 18px;
            margin: -4px 0 -2px 0;
            letter-spacing: -2px;
        }
        /* 小标签 */
        .proxy-badge {
            background: #e0f2fe;
            color: #0369a1;
            padding: 2px 10px;
            border-radius: 20px;
            font-size: 12px;
            display: inline-block;
            margin-right: 8px;
        }
        .ref-badge {
            background: #fef9c3;
            color: #854d0e;
            padding: 2px 10px;
            border-radius: 20px;
            font-size: 12px;
            display: inline-block;
            margin-right: 8px;
        }
        .highlight {
            background: #dcfce7;
            color: #166534;
            padding: 2px 8px;
            border-radius: 16px;
            font-weight: 500;
        }
        /* 列表样式 */
        ul {
            margin: 8px 0 0 0;
            padding-left: 20px;
        }
        li {
            margin-bottom: 5px;
            color: #2d3c50;
        }
        hr {
            border: none;
            border-top: 1px solid #d1d9e6;
            margin: 16px 0 10px 0;
        }
        /* 右侧ref特殊盒子 */
        .ref-box {
            background: white;
            border-radius: 12px;
            padding: 14px;
            border: 1px dashed #f59e0b;
            margin: 15px 0 5px;
        }
        .ref-value {
            background: #f1f5f9;
            font-family: monospace;
            padding: 4px 8px;
            border-radius: 20px;
            display: inline-block;
            margin: 6px 0;
        }
        .auto-unpack {
            background: #f1f5f9;
            border-radius: 20px;
            padding: 4px 12px;
            font-size: 12px;
            color: #334155;
        }
        /* 五号字体全局已定,保持所有字体系列 */
        p, li, div, span, .desc, .flow-step, .section-label {
            font-family: inherit;
        }
        /* 小字引用 */
        .cite {
            color: #6b7b8f;
            font-size: 12px;
            margin-top: 16px;
            text-align: right;
            border-top: 1px solid #e2e8f0;
            padding-top: 12px;
        }
    </style>
</head>
<body>
    <div class="diagram-container">
        <!-- 大标题 -->
        <div class="title">🟢 Vue3 响应式系统原理 · 基于Proxy全面监听</div>
 
        <!-- 三块内容 -->
        <div class="main-panel">
            <!-- 左侧:Proxy优势 -->
            <div class="left-panel">
                <div class="section-label">✨ 基于Proxy · 优势</div>
                <div style="background: #e6f7ff; border-radius: 12px; padding: 12px; border: 1px solid #bae7ff;">
                    <span class="proxy-badge">ES6 Proxy</span><span style="font-weight: 500;"> 取代 Object.defineProperty</span>
                    <ul style="margin-top: 12px;">
                        <li>✅ 拦截对象<strong>各种操作</strong>:读取(get)、设置(set)、删除(deleteProperty)、枚举(ownKeys) 等</li>
                        <li>✅ <strong>全面监听</strong>:属性新增、删除、数组索引/length修改都能捕获</li>
                        <li>✅ 无需递归遍历所有属性,性能更优且支持动态属性</li>
                        <li>✅ 可拦截 <code>in</code> 操作符、<code>for...in</code> 等元操作</li>
                    </ul>
                    <div style="margin-top: 10px; background: #ffffffb3; padding: 8px; border-radius: 8px; font-size: 13px;">
                        <span style="color: #2c3e50;">📋 对比Vue2:</span>无法检测对象属性添加/删除,需用 <code>$set</code>;对数组需重写方法。Proxy完美解决。
                    </div>
                </div>
                <!-- 文献引用[10] -->
                <div class="ref-note">📎 参考文献 [10]: Proxy可以拦截对象的各种操作,包括属性读取、设置、删除、枚举等,实现对对象变化的全面监听。</div>
            </div>
 
            <!-- 中间:核心流程 (依赖收集/触发更新) -->
            <div class="center-panel">
                <div class="section-label">⚙️ 核心流程 · reactive + 依赖追踪</div>
                
                <!-- 步骤1:reactive -->
                <div class="flow-step">
                    <strong>1️⃣ reactive(data) 创建代理对象</strong>
                    <div class="desc">原始对象通过 <code style="background:#e9ecf3; padding:2px 6px;">new Proxy(target, handler)</code> 变为响应式代理。</div>
                </div>
                <div class="arrow-down">▼</div>
 
                <!-- 步骤2:组件渲染/访问 -->
                <div class="flow-step">
                    <strong>2️⃣ 组件渲染过程中访问响应式数据</strong>
                    <div class="desc">例如模板中使用 <code>{{ state.count }}</code> 或 <code>computed</code> 中读取。</div>
                </div>
                <div class="arrow-down">▼</div>
 
                <!-- 步骤3:getter拦截 & 依赖收集 -->
                <div class="flow-step" style="border-left-color: #f59e0b;">
                    <strong>3️⃣ <span class="highlight">getter 拦截</span> → 依赖收集</strong>
                    <div class="desc">触发Proxy的 <code>get</code> 陷阱,将当前副作用(如组件的渲染函数)记录为该属性的依赖。</div>
                    <div style="background: #fff7e6; border-radius: 20px; padding: 4px 10px; margin-top: 8px; font-size:13px;">
                        🧠 依赖关系:target Map (属性 → Set(副作用))
                    </div>
                </div>
                <div class="arrow-down">▼</div>
 
                <!-- 步骤4:数据变化 setter -->
                <div class="flow-step" style="border-left-color: #ef4444;">
                    <strong>4️⃣ 响应式数据变化 🔁 <span class="highlight">setter 拦截</span></strong>
                    <div class="desc">修改属性值触发 <code>set</code> 陷阱,比对变化后进入通知阶段。</div>
                </div>
                <div class="arrow-down">▼</div>
 
                <!-- 步骤5:通知依赖更新 -->
                <div class="flow-step" style="border-left-color: #3b82f6;">
                    <strong>5️⃣ 触发更新 (通知相关依赖)</strong>
                    <div class="desc">从依赖映射中找到所有与该属性相关的副作用(组件渲染函数、计算属性等),加入调度队列。</div>
                </div>
                <div class="arrow-down">▼</div>
 
                <!-- 步骤6:组件重新渲染 -->
                <div class="flow-step">
                    <strong>6️⃣ 组件重新渲染 · 更新DOM</strong>
                    <div class="desc">执行副作用,生成新虚拟DOM,高效更新真实DOM。</div>
                </div>
 
                <!-- 附加说明:依赖收集与触发更新的简洁描述 -->
                <hr>
                <div style="display: flex; gap: 12px; justify-content: space-between; background: #e7f3ff; padding: 10px; border-radius: 12px;">
                    <div><span style="background: #2563eb; color:white; padding:2px 10px; border-radius: 30px;">⬇️ 依赖收集</span> 在getter中建立关系</div>
                    <div>➡️</div>
                    <div><span style="background: #db2777; color:white; padding:2px 10px; border-radius: 30px;">⬆️ 触发更新</span> 在setter中派发任务</div>
                </div>
            </div>
 
            <!-- 右侧:ref概念 -->
            <div class="right-panel">
                <div class="section-label">🔁 ref 包装基本类型</div>
                <div style="background: #fffbeb; border-radius: 14px; padding: 12px; border:1px solid #fde68a;">
                    <span class="ref-badge">ref()</span> 用于 <code>string | number | boolean</code> 等原始值
                    <div class="ref-box">
                        <div style="display: flex; align-items: center; gap: 6px;">
                            <span>🔸 构造:</span>
                            <code style="background:#e9eef3; padding:4px 8px; border-radius: 20px;">ref('hello')</code>
                        </div>
                        <div style="margin: 12px 0 8px 0; background:#e6f7ff; padding: 8px; border-radius: 12px;">
                            ⚡ 返回一个包含 <strong style="color:#b45309;">.value</strong> 属性的对象:
                            <div style="background: #1e293b; color: #facc15; padding: 6px 12px; border-radius: 20px; margin-top: 6px; font-family: monospace;">
                                { value: 'hello' }
                            </div>
                        </div>
                        <div><span class="auto-unpack">✨ 模板中自动解包</span></div>
                        <div style="margin-top: 10px; background:#fff; border-radius: 20px; padding: 6px 10px;">
                            ✅ <code>&lt;div&gt;{{ msg }}&lt;/div&gt;</code>  无需写 <code>msg.value</code>
                        </div>
                        <div style="margin-top: 10px; border-top: 1px dotted #cbd5e1; padding-top: 8px;">
                            🧩 <strong>script中必须使用 .value</strong> 修改/读取
                        </div>
                    </div>
                    <div style="font-size: 13px; margin-top: 8px; background: #d9f99d; padding: 4px 8px; border-radius: 20px;">
                        📦 同样基于Proxy/reactive实现,但通过value属性嵌套保证响应式
                    </div>
                </div>
                <!-- 简洁对比 -->
                <div style="margin-top: 16px;">
                    <span style="background: #cbd5e1; padding:2px 10px; border-radius: 30px;">reactive vs ref</span>
                    <ul style="margin-top: 10px;">
                        <li><strong>reactive</strong>:用于对象/数组,直接代理</li>
                        <li><strong>ref</strong>:用于基本类型,也可包裹对象(但自动用reactive转换深层)</li>
                    </ul>
                </div>
            </div>
        </div>
 
        <!-- 底部整合描述:完全呼应题目内容 -->
        <div style="display: flex; flex-wrap: wrap; gap: 16px; margin-top: 24px; background: #f1f5f9; border-radius: 20px; padding: 14px 18px;">
            <div style="flex:1; min-width: 200px;">
                <span style="font-weight: 600;">📌 Proxy全面监听</span>:get/set/deleteProperty/ownKeys · 全面代替Vue2的Object.defineProperty
            </div>
            <div style="flex:1; min-width: 220px;">
                <span style="font-weight: 600;">🎯 核心流程闭环</span>:reactive → 渲染访问 → getter收集 → setter触发 → 通知更新 → 重绘
            </div>
            <div style="flex:1; min-width: 180px;">
                <span style="font-weight: 600;">🔖 ref自动解包</span>:模板中直接使用标识符,底层访问.value
            </div>
        </div>
 
        <!-- 完整引用及字体声明 -->
        <!-- <div class="cite">
            <span>📖 内容依据:Vue3响应式原理 · 基于Proxy的优势、核心流程 (依赖收集/触发更新) 及 ref 包装基本类型。 </span>
            <span style="margin-left: 12px;">🔤 全图字体: 宋体 (SimSun) 五号 (14px)</span>
        </div> -->
    </div>
    <!-- 确保任何位置都强制宋体(备用) -->
    <div style="display: none;">字体检测</div>
</body>
</html>