你想从子组件里控制外层那个 transition?Chrome 147 今天把这件事彻底原生化了
写 SPA 页面过渡动画,你大概已经用过 document.startViewTransition()。但如果你试过在组件里启动 transition,再从另一个地方访问它的状态,会发现这个 API 留了一个不大不小的坑——你得手动把 startViewTransition() 的返回值保存到一个外部变量里,才能在别处拿到 transition 对象。Chrome 147 解决了这个问题。
那个手动保存返回值的问题
Element.startViewTransition() 返回一个 ViewTransition 对象,这个对象有 .ready、.finished、.skipTransition() 这些有用的成员。但如果你不是在发起处访问它,而是想从子组件或者回调函数里访问transition状态,这个对象就必须提前存到一个公共位置。
典型写法是这样的:
let currentVT; // 全局或共享状态
function startTransition() {
container.startViewTransition(() => {
updateDOM();
});
// 手动保存返回值
currentVT = container.startViewTransition(() => {
updateDOM();
});
}
// 想取消 transition,得靠这个外部变量
function cancelIfNeeded() {
if (currentVT) {
currentVT.skipTransition();
}
}
问题在于:变量传来传去容易造成状态不同步,而且如果 transition 从组件内部发起,想从另一个模块访问,你得额外部署一套共享机制。
element.activeViewTransition 登场
Chrome 147 给 Element 加了一个只读属性 activeViewTransition,任何时候你想知道一个元素上有没有正在进行的 View Transition,直接读这个属性就行,不需要任何外部变量:
function startTransition() {
// 发起 transition,不需要保存返回值
container.startViewTransition(() => {
updateDOM();
});
}
// 任何地方直接查
function cancelIfNeeded() {
const vt = container.activeViewTransition;
if (vt) {
vt.skipTransition();
}
}
// 返回 null 说明没有正在进行的 transition
if (!container.activeViewTransition) {
console.log(目前没有动画在进行);
}
实际用得上的三个场景
场景一:子组件控制外层 transition
Modal 关闭时,触发父容器的 transition:
closeButton.addEventListener(click, () => {
const dialog = document.querySelector(dialog);
const container = dialog.parentElement;
const vt = container.activeViewTransition;
if (vt) {
// 等 transition 结束后再关闭
vt.waitUntil(dialog.close());
} else {
dialog.close();
}
});
场景二:动画序列编排
列表项移动完成后,自动触发下一段高亮动画:
async function moveItem(from, to) {
const list = document.querySelector(ul);
list.startViewTransition(() => {
reorderItems(from, to);
});
// 直接从元素上拿到 transition,等它完成
await list.activeViewTransition.finished;
highlightMovedItem(to);
}
场景三:调试状态面板
不需要额外部署状态变量,实时显示 transition 运行状态:
setInterval(() => {
const vt = document.querySelector(.app-container).activeViewTransition;
statusIndicator.textContent = vt ? `Transition: ${vt.ready ? ready : pending}` : Idle;
}, 100);
和 Document.activeViewTransition 的区别
| 属性 | 适用场景 | 触发方式 |
|---|---|---|
| Document.activeViewTransition | document.startViewTransition() | 整页过渡 |
| element.activeViewTransition | element.startViewTransition() | 组件级过渡 |
两者可以同时存在,互不干扰。
浏览器支持
Chrome 147+ 和 Edge 147+。Safari 和 Firefox 尚未支持,渐进增强思路:
if (!container.activeViewTransition) {
// 没有 API 时直接执行,不做动画
updateDOM();
return;
}
container.startViewTransition(() => updateDOM());
下一步
打开 DevTools,在你的 SPA 项目里搜索 startViewTransition——如果找到任何手动保存 transition 返回值的代码,立即用 activeViewTransition 重构掉。
评论区
登录后可评论。