首页
/ @angular/animations/browser 公共 API 全景:AnimationDriver 抽象与 NoopAnimationDriver 的实现、接入与迁移指南

@angular/animations/browser 公共 API 全景:AnimationDriver 抽象与 NoopAnimationDriver 的实现、接入与迁移指南

2026-09-07 09:27:40作者:虞亚竹Luna

导读

@angular/animations/browser 是 Angular 动画系统在浏览器端与无动画场景下的运行时核心模块。本文以其 API 报告文件 goldens/public-api/animations/browser/index.api.md 为骨架,完整梳理其中声明的两个公共符号 AnimationDriver 抽象类与 NoopAnimationDriver 实现类,逐一解读每个抽象方法的语义、参数与返回值,并结合本仓库源码揭示其底层实现(如样式属性校验、DOM 祖先遍历、Shadow DOM 兼容处理),最后说明它在真实应用中的注入接入方式(浏览器 Web Animations 驱动与 Noop 驱动)以及自 v20.2 起被 animate.enter / animate.leave 取代的迁移方向。读完本文,你将能读懂该类 API 报告的语法、掌握动画驱动层的扩展点,并能在测试或自定义渲染环境中正确选用与替换动画驱动。

一、这份文档是什么:Angular 的 API 报告(golden file)

仓库根目录下 goldens/public-api 存放着各包经由 API Extractor 自动生成的 API 报告(俗称 golden file)。index.api.md 开头的三行即为报告元数据:

  • 标题行声明本报告对应的入口包名为 @angular/animations_browser
  • “Do not edit this file.” 提示该文件由工具自动生成、不可手改;
  • 文件内容被包裹在一个 ts 代码块中,// @public 表示该符号属于公共 API 面,受公开契约保护;改动这些签名需要同步更新 golden 文件并经 CI 校验。

这份报告揭示了一个重要事实:@angular/animations/browser 对外暴露的公共符号只有两个——抽象类 AnimationDriver 与其 Noop 实现 NoopAnimationDriver(此外报告末尾注明 “No @packageDocumentation comment for this package”)。二者在源码中的真实定义位于 packages/animations/browser/src/render/animation_driver.ts,并通过 public_api.tssrc/browser.tsexport {AnimationDriver, NoopAnimationDriver} 逐级导出(入口 index.ts 仅用于编辑期语言服务与构建校验)。

二、核心符号总览:两个公共类型与其弃用状态

报告顶部对两个类型都标注了相同的弃用信息:

// @public @deprecated (undocumented)
// 20.2 起弃用:请改用 animate.enter 或 animate.leave,计划在 v23 移除

也就是说,自 Angular v20.2 起,动画驱动层这套“面向触发(trigger)的 DSL 动画”基础设施正逐步退出历史舞台,替代品是新的 animate.enter / animate.leave 能力;但当前版本中该模块仍完整可用,且 platform-browser/animations 的生产路径仍依赖它(详见第五节)。

两个类型的职责划分非常清晰:

符号 类型 职责
AnimationDriver abstract class 定义动画运行时的“驱动契约”,抽象出元素查询、样式校验/读取、动画执行等原语,供不同渲染后端实现
NoopAnimationDriver class implements AnimationDriver 不产生真实动画的空实现:校验逻辑照常执行,但 animate 只返回一个立即“空转”的播放器

三、AnimationDriver:驱动层的抽象契约逐一拆解

抽象类共定义了 1 个静态成员与 7 个成员方法(其中 1 个可选),下面结合 源码 逐条说明其语义与签名含义。

3.1 静态成员 AnimationDriver.NOOP

static NOOP: AnimationDriver;  // @deprecated

一个直接初始化为 NoopAnimationDriver 实例的静态单例,源码注释明确建议改用 NoopAnimationDriver 类本身。历史遗留用途是在不便于注入的地方直接取用空驱动。

3.2 animate():执行动画的核心方法

abstract animate(
  element: any,
  keyframes: Array<Map<string, string | number>>,
  duration: number,
  delay: number,
  easing?: string | null,
  previousPlayers?: any[],
  scrubberAccessRequested?: boolean,
): any;

参数语义:

  • element:动画作用的 DOM 元素;
  • keyframes:关键帧集合,其元素类型是 Map<string, string | number>(注意:不是 CSS 风格的 keyframe 对象数组,而是 ES Map,键为属性名与 offset,值为属性值或归一化后的数字);关于 Map 形式的关键帧可对照 animation_timeline_builder.ts 中对关键帧的组装逻辑;
  • duration / delay:动画时长与延迟(毫秒);
  • easing:可选缓动函数(如 'ease-in-out' 或 cubic-bezier 串),可为 null
  • previousPlayers:前一轮动画的播放器,供新动画做样式衔接与插值继承;
  • scrubberAccessRequested:是否请求“擦洗器”访问能力(拖动时间轴预览类场景)。

返回类型为 any,实际约定是返回一个 AnimationPlayer。可参考 Web Animations 后端的真实用法 web_animations_driver.ts:它依据 delay == 0 决定 fill: 'both' | 'forwards',仅在 easing 非空时才写入 playerOptions['easing'](源码注释指出,空值 easing 在部分浏览器会触发错误,见 issue #9752 相关处理),随后会把 previousPlayersWebAnimationsPlayercurrentSnapshot 汇入前一状态以平衡关键帧,再执行 normalizeKeyframesbalancePreviousStylesIntoKeyframes,最后将不可动画的样式单独打包(packageNonAnimatableStyles)交给 WebAnimationsPlayer

3.3 computeStyle():读取元素当前样式

abstract computeStyle(element: any, prop: string, defaultValue?: string): string;

给定元素与属性名,返回其当前计算样式;当无法取得时回退到 defaultValue

3.4 containsElement() / getParentElement():DOM 层级关系

abstract containsElement(elm1: any, elm2: any): boolean;   // elm1 是否包含 elm2
abstract getParentElement(element: unknown): unknown;       // 返回父节点,无父时返回 null

这两个方法支撑动画触发器的“祖先后代”判定与元素树遍历。

3.5 query():按选择器查询元素

abstract query(element: any, selector: string, multi: boolean): any[];

element 范围内执行选择器查询:multitrue 时返回全部命中项,为 false 时结果数组最多含 1 项。

3.6 validateStyleProperty() 与可选的 validateAnimatableStyleProperty()

abstract validateStyleProperty(prop: string): boolean;
abstract validateAnimatableStyleProperty?: (prop: string) => boolean;  // 可选

前者校验某属性是否为合法 CSS 样式属性;后者(可选实现)进一步校验该属性能否被当前驱动动画化,例如 Web Animations 后端用预置集合 animatable_props_set.ts 做白名单判断。是否实现该可选方法,是区分驱动能力“能认样式但无法播放动画”与“能真正播放动画”的关键信号。

四、NoopAnimationDriver:一切方法都有确定语义的空实现

NoopAnimationDriver 是唯一随公共 API 导出的 AnimationDriver 具体实现,在 源码 中被标注为 @Injectable()(因此报告里出现 ɵfac 工厂声明与 ɵprov 注入声明两个私有静态成员),这意味着它可以直接参与 Angular 依赖注入。每个方法的行为都与 shared.ts 中的纯函数助手一一对应,可逐行对照 render/shared.ts

方法 Noop 行为 底层助手(shared.ts) 实现要点
validateStyleProperty(prop) 返回该属性是否为合法 CSS 属性 validateStyleProperty 惰性缓存 body 节点与 WebKit 探测结果('WebkitAppearance' in body.style);对非 -webkit- 前缀属性先做 prop in style 判断,失败时再补测 'Webkit' + 大写首字母 的驼峰形式
containsElement(elm1, elm2) 沿 elm2 的父链上溯判断是否命中 elm1 containsElement 依赖 getParentElement 逐级上溯直至 null
getParentElement(element) 返回父节点或 null getParentElement 同时读 `element.parentNode
query(element, selector, multi) 执行标准选择器查询 invokeQuery multi 为真用 querySelectorAll 转数组;否则 querySelector 命中则包成单元素数组,未命中返回空数组
computeStyle(element, prop, defaultValue?) 直接返回 defaultValue || '' Noop 语义的关键差异:不做真实计算样式读取(Web Animations 后端才通过 util.computeStyle 读取真实值)
animate(...) 返回 new NoopAnimationPlayer(duration, delay) 关键帧被整体忽略,只保留时长/延迟信息,动画“瞬间完成”;对比报告,Noop 未覆盖可选的 validateAnimatableStyleProperty,即不声明“可动画化”白名单能力

NoopAnimationPlayer 来自 packages/src/animations,由 @angular/animations 提供。正是这套“参数照收、执行空转”的设计,让 NoopAnimationDriver 既能无缝承接上层所有动画调用链,又能在禁用动画场景(如 SSR、测试、无障碍降级)中零成本运行。

五、驱动如何被真实注入:BROWSER_ANIMATIONS_PROVIDERS 接入路径

虽然 golden 文件只暴露了 AnimationDriver 与 Noop 实现,但在仓库中真正“能播放动画”的浏览器驱动是私有的 WebAnimationsDriver(经 private_export.tsɵWebAnimationsDriver 导出,供上层包内部使用)。二者的选择逻辑集中在 packages/platform-browser/animations/src/providers.ts

export const BROWSER_ANIMATIONS_PROVIDERS: Provider[] = [
  {
    provide: AnimationDriver,
    useFactory: () =>
      typeof ngServerMode !== 'undefined' && ngServerMode
        ? new NoopAnimationDriver()          // 服务端渲染:不播放真实动画
        : new WebAnimationsDriver(),          // 浏览器端:Web Animations API
  },
  { provide: ANIMATION_MODULE_TYPE,
    useFactory: () =>
      ngServerMode ? 'NoopAnimations' : 'BrowserAnimations' },
  ...SHARED_ANIMATION_PROVIDERS,
];

同文件中的 BROWSER_NOOP_ANIMATIONS_PROVIDERS 则固定走 {provide: AnimationDriver, useClass: NoopAnimationDriver} 并将 ANIMATION_MODULE_TYPE 标为 'NoopAnimations'SHARED_ANIMATION_PROVIDERS 会连带提供 AnimationStyleNormalizerAnimationEngineInjectableAnimationEngine,在 ngOnDestroyflush() 所有动画)与 RendererFactory2 的动画包装。这一段代码足以证明本文主角在框架内的实际位置:AnimationDriver 是渲染层唯一替换点,应用选择“真实动画”还是“禁用动画”,本质上就是选择 WebAnimationsDriver 还是 NoopAnimationDriver 注入给 AnimationEngine

顺带说明:WebAnimationsDrivervalidateStyleProperty / validateAnimatableStyleProperty 都带 ngDevMode 守卫,生产模式下直接返回 true 以省去运行时校验(见 web_animations_driver.ts),这解释了“为什么 dev 模式会报非法样式属性而 prod 不会”。

六、测试场景:MockAnimationDriver 与规格测试

在自动化测试中,通常需要“记录但不真正播放”的驱动以断言调用序列。仓库在 packages/animations/browser/testing 子包提供了 MockAnimationDrivermock_animation_driver.ts),它同样 implements AnimationDriver、同样带有自 v20.2 起的弃用标注,并维护一个静态的 log: AnimationPlayer[] 用来累积每次 animate 调用产生的播放器,供测试断言。其样式校验与查询等助手复用与 NoopAnimationDriver 完全相同的底层函数,区别在于 animate() 会真实构造并记录播放器而非直接丢弃。

本包自带的规格测试同样是对接口语义最直接的佐证,值得继续研读:

七、自 v20.2 起的弃用与迁移提示

报告中反复出现的 @deprecated 20.2 需要开发者留意:Angular 动画的演进方向是把原有“@-trigger + 状态转场”的 DSL 能力收敛为更贴近新一代响应式(signal-based)心智模型的 animate.enter / animate.leave,因此 AnimationDriverNoopAnimationDriver 乃至测试用的 MockAnimationDriver 都被标注“计划在 v23 移除”。

对本模块的读者而言,迁移提示可以归纳为三条:

  1. 应用代码尽量不直接依赖这两个符号:正常情况下它们只应作为 DI token/实现出现在框架与库内部(如 providers.ts);应用自定义动画驱动属高级定制场景,应评估是否可用新 API 表达。
  2. 升级路径已就绪:既然驱动选择在 v20 仍由 platform-browser/animations 的 providers 自动完成,直接迁移到 animate.enter / animate.leave 前,现有动画在移除前不受影响。
  3. 留意构建期黄金文件:本 API 报告受 CI 守护,任何对这两个公共类型签名的修改(哪怕只是参数注释)都必须同步重生成 goldens/public-api/animations/browser/index.api.md,这也是解读 Angular 公共 API 变更时最权威的“变更记录”入口。

结语

通过一张 API 报告出发,本文梳理了 @angular/animations/browser 仅有的两个公共类型:AnimationDriver 抽象了“查询元素—校验样式—执行动画”的完整驱动契约,NoopAnimationDriver 则以“校验真实、播放空转”的策略提供了零成本实现。结合 animation_driver.tsshared.tsproviders.ts,你可以看到一条完整的链路:从接口定义、纯函数助手,到 DI 提供方与 SSR 分支选择。理解这条链路后,无论是排查动画不生效(是否误用了 Noop 驱动)、理解样式校验报错差异,还是评估自定义驱动的可行性,你都能在源码层找到依据——而这正是把一份自动生成的 API 报告读成“架构说明书”的价值所在。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391