虚拟 DOM 本身不直接处理动画,但通过 Transition 组件声明式管理 enter/leave 阶段的 CSS 类与 JS 钩子,并结合 patch 过程中的 insert/remove/update 钩子实现精准帧同步动画控制。

虚拟 DOM 本身不直接处理动画,但它为动画过渡提供了关键的时机控制和状态对比能力。Transition 组件(如 Vue 的 )和 Patch 钩子(如 Vue 的 updated、beforeUpdate,或更底层的 patch 过程中的 insert、remove、update 钩子)协同工作,才能在 DOM 节点进入/离开/更新时精准触发动画。
Transition 组件负责声明式生命周期钩子
它不是渲染真实 DOM,而是通过包裹子元素,监听其 vnode 的“存在性变化”(比如从 null → vnode 或 vnode → null),并自动注入 enter / leave / appear 等阶段的 CSS 类或 JavaScript 钩子:
- 当元素即将插入时,添加
v-enter类,下一帧切换为v-enter-active,动画结束后移除两者 - 当元素即将移除时,添加
v-leave类,再立即切换为v-leave-active,动画完成后再触发真实 DOM 删除 - 这些类名变更由 Transition 内部调用
nextTick+getComputedStyle强制重排实现帧同步
Patch 钩子提供细粒度 DOM 操作时机
在虚拟 DOM 的 diff patch 过程中,框架(如 Vue)会为每个 vnode 绑定原生 DOM 操作钩子。这些钩子比组件级生命周期更底层、更及时:
-
insert(el):节点已挂载到真实 DOM 后立即执行,适合启动入场动画(如el.animate()或requestAnimationFrame) -
remove(el, done):节点将被移除前触发,必须调用done()告知 patch 等待动画结束,否则会跳过动画直接删除 -
update(oldVnode, vnode):适用于属性/样式变更动画(如宽度、颜色渐变),可对比oldVnode.data.style和vnode.data.style触发补间
结合使用的典型场景
例如实现一个列表项的位移+缩放过渡动画:
- 用
包裹 v-for 列表,自动管理每项的 key 和 enter/leave 流程 - 在 vnode 创建时(如 render 函数中),为每个 item vnode 设置
insert钩子:读取目标位置(可通过el.getBoundingClientRect()获取初始坐标),再用getComputedStyle读取目标样式,最后调用el.animate()执行位移+scale 动画 - 在
update钩子中检测oldVnode.key !== vnode.key或数据变动,判断是否发生排序,进而计算旧位置到新位置的 transform 差值并补间
注意事项
避免在 Patch 钩子中直接修改响应式数据(会触发新一轮 patch,可能死循环);动画时长需与 CSS transition-duration 或 JS 动画时长严格对齐;remove 钩子必须调用 done,否则 DOM 不会真正卸载。










