登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  前端

JavaScript Element.getAnimations 怎样收集子树动画对象

来源:17golang原创

时间:2026-10-27 14:46:09 243浏览 收藏

热门推荐
漫画APP
动画内容聚合,热门资源快捷查看
立即下载

如果你要在关闭卡片、切换路由前等动画结束,直接调用 container.getAnimations() 往往只能拿到容器自身的动画。要把后代元素和它们的伪元素也纳入集合,应使用 container.getAnimations({ subtree: true })。返回值是 Animation[],可继续等待每个对象的 finished Promise。

官方地址:https://developer.mozilla.org/en-US/docs/Web/API/Element/getAnimations

要点速览
  • 默认范围是当前元素;subtree: true 才会递归包含后代和相关伪元素。
  • 返回数组同时可能包含 CSS Animation、CSS Transition 和 Web Animations 创建的对象。
  • pseudoElement 用于限定伪元素;与 subtree 同时给出时,以伪元素目标为准。

先区分当前元素与子树范围

Element.getAnimations() 的默认语义是“影响这个元素的动画”。它不是遍历 DOM 的通用选择器,也不会因为元素里面有子节点就自动把子节点动画带回来。比如卡片本身没有动画,卡片里的图标正在旋转,默认调用可能得到空数组。

需要管理一个组件的完整退场状态时,把范围明确写成 subtree: true。这个选项会把当前元素后代上的动画也纳入,包括附着在当前元素或后代上的 CSS 伪元素动画。集合里的对象不是动画名称,而是可以播放、暂停、取消或等待的 Animation 实例。

Element.getAnimations 当前元素与 subtree 子树范围的静态结构说明图
图1:范围说明图,比较当前元素、后代节点、伪元素与 Animation 集合的关系。

用 subtree true 收集 Animation 对象

下面的例子把一个面板及其后代动画收集起来,再输出每个动画的播放状态和目标元素。示例只展示静态关系;具体数量取决于页面当前的 CSS 动画、过渡和脚本动画。

const panel = document.querySelector(".panel");

// 子树范围会包含 panel 后代及相关伪元素的动画对象。
const animations = panel?.getAnimations({ subtree: true }) ?? [];

for (const animation of animations) {
  // CSS 动画或过渡的 effect 可能存在,但 target 也可能是 null。
  const effect = animation.effect;
  const target = effect && "target" in effect ? effect.target : null;
  console.log({
    state: animation.playState,
    target: target instanceof Element ? target : null,
  });
}

这里的 effect.target 适合做定位或统计,不要把它当成永远存在的元素引用:动画效果可能没有具体目标,目标也可能在组件卸载过程中变为不可用。若只是等待全部动画完成,不必自行递归子树或按选择器再查一次。

等待动画完成后再移除组件

退场动画最常见的需求是“视觉结束后再删除 DOM”。Animation.finished 会提供当前动画完成时兑现的 Promise;把数组映射后交给 Promise.all,就能等待集合中的所有动画。

async function removeAfterAnimations(panel) {
  // 收集当前组件及子树中已经存在或即将影响它的动画。
  const animations = panel.getAnimations({ subtree: true });

  // 空数组会立即完成,组件没有动画时也能安全继续。
  await Promise.all(animations.map((animation) => animation.finished));

  // 等待完成后再次确认节点仍在文档中,避免重复清理。
  if (panel.isConnected) {
    panel.remove();
  }
}

如果动画被取消,finished 可能以拒绝结束;真实组件应根据业务决定捕获取消异常,或在调用 cancel() 前后使用统一的清理分支。不要把等待 Promise 当作动画仍然存在的保证,页面切换和样式变更都可能改变集合。

Animation 对象、effect.target、finished Promise 与组件生命周期的静态关系说明图
图2:生命周期结构图,说明收集结果如何连接到目标对象、完成 Promise 和组件清理。

伪元素参数与兼容边界

如果只关心 ::before 或 ::after,可以传入 pseudoElement。它表达的是目标限定,不是 CSS 选择器;传入无效伪元素时可能抛出 SyntaxError。同时指定 pseudoElement 和 subtree 时,应按只指定伪元素来理解,不要以为会得到“整个子树里的同名伪元素”。

function readAfterAnimations(element) {
  try {
    // 只查询当前元素 ::after 上的动画,不递归其他后代。
    return element.getAnimations({ pseudoElement: "::after" });
  } catch (error) {
    // 参数不被当前环境接受时,返回空集合交给上层降级处理。
    if (error instanceof DOMException && error.name === "SyntaxError") {
      return [];
    }
    throw error;
  }
}

该 API 在现代浏览器中已经广泛可用,但业务仍应允许空数组:动画可能尚未开始、已经结束,或者用户启用了减少动态效果。真正需要兼容旧环境时,可以让组件保留固定的清理超时,而不是重新手写 DOM 深度遍历来猜测动画。

性能与生命周期注意事项

  • 把收集动作放在关闭、路由切换或状态提交等明确时机,不要在 requestAnimationFrame 每帧调用。
  • 范围越大的组件,返回对象越多;只管理一个按钮时优先调用按钮自身,不要无条件向上取整棵页面。
  • 保存数组只是保存当时的快照。动画新增、取消或被替换后,需要按业务时机重新收集。

相关问题

默认调用为什么收不到子元素动画?

因为默认 subtree 为 false,需要明确传入 { subtree: true }。

getAnimations 能只返回 CSS 动画吗?

它返回影响目标的 Animation 对象集合,可能混合 CSS Animation、CSS Transition 和 Web Animations;需要按 effect、状态或目标再做业务筛选。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>