上海好的高端网站建设合肥集团网站建设哪个好
2026/5/25 4:35:42 网站建设 项目流程
上海好的高端网站建设,合肥集团网站建设哪个好,2021年工程造价信息,网页设计的实训总结基于 Vue 3.4#xff08;runtime-core#xff09;一、组件更新链路 响应式数据变化 ↓ 触发 effect#xff08;scheduler#xff09; ↓ 组件 render 函数重新执行 ↓ 生成新的 VNode Tree ↓ patch(oldVNode, newVNode) ↓ 精确更新真实 DOM虚拟 DOM 的职责#xff1a;描…基于 Vue 3.4runtime-core一、组件更新链路响应式数据变化 ↓ 触发 effectscheduler ↓ 组件 render 函数重新执行 ↓ 生成新的 VNode Tree ↓ patch(oldVNode, newVNode) ↓ 精确更新真实 DOM虚拟 DOM 的职责描述 UI 结构​diff 的职责最小化 DOM 更新二、Vue3 的虚拟 DOM 本质Vue3 中的 VNode 是一个​高度优化的 JS 对象​interface VNode { type: string | Component props: Recordstring, any | null children: string | VNode[] | null key: any el: HTMLElement | null // 对应真实 DOM shapeFlag: number // 节点类型位运算标识 patchFlag: number // 告诉 diff哪里可能变 dynamicProps: string[] | null // 动态 ptops 列表 }三、diff 的目标单个 DOM 之间的对比一般只需要对比节点类型、属性、文本内容等而最最重要的其实是他们子节点的对比过程因此下面主要讲解子节点的对比。diff 的输入oldChildren: VNode[] newChildren: VNode[]diff 的目标只有三个复用能复用的 DOM最少的 DOM 操作保证最终 DOM 顺序正确diff 不关心“组件更新”只关心“同一父节点下 children 的变化”patchKeyedChildren( c1: VNode[], // oldChildren c2: VNode[], // newChildren container: Element )前提条件children 是数组并且 ​有 key​无 key 是另一套退化逻辑四、Vue3 diff 的完整阶段Vue3 的 diff ​严格分 5 个阶段​而且​顺序不能乱​1️⃣ 从头同步 2️⃣ 从尾同步 3️⃣ 新节点多 → 挂载 4️⃣ 旧节点多 → 卸载 5️⃣ 中间乱序 diff重点一阶段从头同步let i 0 while ( i e1 i e2 isSameVNodeType(c1[i], c2[i]) ) { patch(c1[i], c2[i]) i }old: A B C D new: A B E D ↑A A→ patchB B→ patchC ! E→ 停为什么要做这一步其实我们现实业务中“头部稳定”是最常见情况列表 append局部更新这是一个O(n) 的优化。二阶段从尾同步while ( i e1 i e2 isSameVNodeType(c1[e1], c2[e2]) ) { patch(c1[e1], c2[e2]) e1-- e2-- }old: A B C D new: A E C D ↑D DC C停尾部稳定在 prepend / insert 场景很常见三阶段只剩新节点if (i e1 i e2)说明oldChildren 已处理完newChildren 还有剩余old: A B new: A B C D ↑ ↑while (i e2) { patch(null, c2[i], container, anchor) i }纯新增直接 mount零 diff 成本四阶段只剩旧节点if (i e2 i e1)old: A B C new: A B ↑while (i e1) { unmount(c1[i]) i }到这里为止90% 的列表更新已经解决了。只有剩下“中间乱序”的情况才进入真正的复杂 diff。五阶段中间乱序 diff这里你要好好听了有一步走神后面就听不懂了此时新旧元素 index 数组old: [i ... e1] new: [i ... e2]例如old: A B C D E new: B A E C D头和头比较不同停止然后尾和尾比较不同停止所以这个整体进入中间乱序 diff 的比较过程。第 1 步建立 newChildren 的 key → index 映射const keyToNewIndexMap new Map() for (let j i; j e2; j) { keyToNewIndexMap.set(c2[j].key, j) }​目的​O(1) 数组直接查找新节点位置避免 O(n²)newChildren: index: 0 1 2 3 4 node: B A E C D构建 Mapnode - index{ B → 0, A → 1, E → 2, C → 3, D → 4 }第 2 步遍历旧节点尝试复用const newIndexToOldIndexMap new Array(toBePatched).fill(0)遍历 oldChildrenfor (let j i; j e1; j) { const oldVNode c1[j] const newIndex keyToNewIndexMap.get(oldVNode.key) if (newIndex undefined) { unmount(oldVNode) } else { newIndexToOldIndexMap[newIndex - i] j 1 patch(oldVNode, c2[newIndex]) } }关键设计点为什么存j 10 → 表示“新节点”所以如果存在复用节点至少为1否则有歧义 0 → 表示旧节点索引 1遍历old : A B C D E index: 0 1 2 3 4构建新节点数组索引到旧节点数组索引的映射表newIndexToOldIndexMap []数组长度 newChildren 中“乱序区间”的长度下标 newIndex新节点的位置值 oldIndex 1第 3 步判断是否需要移动moved 标记if (newIndex maxNewIndexSoFar) { moved true } else { maxNewIndexSoFar newIndex }如果 newIndex 出现逆序说明顺序乱了。这是什么意思呢看下面示例演示依次遍历旧节点遍历 old[0] A在 new 中 index 1记录0 1 1oldIndex1newIndexToOldIndexMap:​[_, 1, _, _, _]记录索引为 1 对应这 newIndex新节点的索引位置遍历 old[1] BnewIndex 0记录1 1 2[2, 1, _, _, _] **这里已经出现逆序21**→moved true遍历 old[2] CnewIndex 3记录2 1 3[2, 1, _, 3, _]遍历 old[3] DnewIndex 4记录3 1 4[2, 1, _, 3, 4]遍历 old[4] EnewIndex 2记录4 1 5[2, 1, 5, 3, 4]最终结果newIndexToOldIndexMap [2, 1, 5, 3, 4]含义如果你看到这里可以完全看懂那么恭喜你第一个难点已经攻破。第 4 步计算最长递增子序列LIS只有在if (moved) { const increasingNewIndexSequence getSequence(newIndexToOldIndexMap) }newIndexToOldIndexMap: [2, 1, 5, 3, 4] LIS [1, 3, 4] // 对应的是 A - C - DLIS 对应的节点相对顺序已经正确不需要移动 DOMA - C - D第 5 步倒序遍历执行 DOM 操作for (let j toBePatched - 1; j 0; j--) { const newIndex j i const newVNode c2[newIndex] const anchor nextIndex c2.length ? c2[nextIndex].el : null if (newIndexToOldIndexMap[j] 0) { patch(null, newVNode, container, anchor) } else if (moved) { if (!isInLIS(j)) { move(newVNode, container, anchor) } } }为什么要 ​倒序​保证 anchor 永远是稳定的 DOM。倒序处理 newChildrenD → C → E → A → B1️⃣ 处理 D在 LIS 不动DOM 还是A B C D E2️⃣ 处理 C在 LIS 不动3️⃣ 处理 E❌ 不在 LIS 移动 E 到 C 前面A B E C D4️⃣ 处理 A在 LIS 不动5️⃣ 处理 B❌ 不在 LIS 移动 B 到 A 前面B A E C D最终 DOM 结构达到正确。LIS 节点就像一排站得顺序已经对的柱子Vue3 只需要把站错位置的挪到正确的位置。五、Vue3 diff 的完整决策树children diff │ ├─ 头部同步 ├─ 尾部同步 ├─ 纯新增 ├─ 纯删除 └─ 中间乱序 ├─ key → index 映射 ├─ 旧节点复用 / 卸载 ├─ 判断是否需要移动 ├─ LIS └─ 倒序 mount / move复杂度分析​Vue3 diff 的最坏复杂度O(n log n)​但大部分真实场景接近 O(n)。为什么 Vue3 diff 比 Vue2 强阶段化 diff不是全量递归LIS 最小移动编译期 patchFlag 极大减少进入 diff 的节点数量Block Tree 让 diff 只遍历“动态节点”六、Vue3 为什么比 Vue2 diff 快编译期 patchFlag模板div{{ count }}/div编译后createElementVNode(div, null, count, 1 /* TEXT */)patchFlag 告诉 diff“只需要比对文本”跳过 props / children / keydynamicProps 精确比对div :idid :classcls/divdynamicProps [id, class]不再遍历所有 props静态提升hoistStaticconst _hoisted_1 /*#__PURE__*/ createElementVNode(...)静态节点不参与 diff直接复用Block Tree块级优化Vue3 会把动态节点收集成一个 blockopenBlock() createElementBlock(...)diff 只遍历动态子节点。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询