前言

上面是一个路由切换的动画。以前,我们想要实现这个效果,需要很多 hack
的方法。但是现在,不管你使用的是什么框架,什么路由,只需要几行代码就可以实现这个效果。
这种革命性的改变得益于浏览器原生 API 的支持。而在 React 生态中,这个特性的支持更是让人兴奋。
随着 Add ViewTransition Component 的合入,
React 官方终于支持了 View Transition API,这是自从 react
宣布 react hooks
以后我最喜欢的一个特性。
为什么需要 View Transition API
在 react
中,想要实现离场动画比入场动画要麻烦很多,因为 react
的组件在卸载的时候,节点会直接从 dom
中移除,而不会等待动画结束再移除。
在以前的 如何实现优雅的离场动画 这篇文章中, 我介绍过使用 framer-motion
来实现离场动画。
主要原理是记录当前需要执行离场动画的组件,在组件卸载阻默认行为,直到离场动画完成以后再卸载组件。
要完成这个过程,需要大量的 JS 代码。而 View Transition API
是 WEB API
, 核心原理就是构建了两种新的伪元素
::view-transition-old(name)
::view-transition-new(name)
用来保存当前视图的快照,他们只短暂存在于视图过渡期间,随后立即销毁,我们可以直接使用 CSS
来指定样式。完美解决了以前离场动画的痛点。
使用 View Transition API 实现几个简单的动画
1. 路由切换动画
文章开头的路由切换动画,一共就以下几行代码.
import { unstable_ViewTransition as ViewTransition } from "react";
// 使用 ViewTransition 包裹需要执行动画的元素
<ViewTransition name="page-transition">
{children}
</ViewTransition>
此时自动就会给路由切换加上一个淡入淡出的动画,我们可以使用 CSS
来指定动画的样式。
::view-transition-old(page-transition) {
animation: slide-out 0.5s ease-out both;
}
::view-transition-new(page-transition) {
animation: slide-in 0.5s ease-out both;
animation-delay: 300ms;
}
2. 元素删除动画

import { unstable_ViewTransition as ViewTransition } from "react";
const initialBoxes = [
{ id: 1, name: "nextjs" },
{ id: 2, name: "nestjs" },
{ id: 3, name: "hono" },
{ id: 4, name: "remix" },
{ id: 5, name: "midway" },
];
function deleteTransition() {
const [box, setBox] = useState(initialBoxes);
const handleDelete = (id: number) => {
startTransition(() => {
setBoxes(boxes.filter((box) => box.id !== id));
});
};
return (
<div className="flex flex-wrap gap-4">
{boxes.map((box) => (
<ViewTransition key={box.id} name={box.name}>
<div className="relative w-32 h-32 border-2 border-blue-500 rounded-lg flex items-center justify-center">
<button
onClick={() => handleDelete(box.id)}
className="absolute top-2 right-2 text-blue-500 w-6 h-6 rounded-full cursor-pointer"
>
×
</button>
{box.name}
</div>
</ViewTransition>
))}
</div>
);
}
相比于路由切换的动画,除了 ViewTransition
包裹元素以外,还需要使用 startTransition
来包裹 setState
的调用,就可以完成一个非常平滑的元素删除动画了。
为什么之前 react
不支持 View Transition API
在 react
中是有虚拟 dom 和批量更新机制的,而 View Transition API
则是期望在其回调函数中立即发生 DOM 变化。因此可能在 react
完成页面更新的时候,
生成的快照早已经被销毁了,所以自然就不起作用了。
react
的支持会对以后有什么影响
虽然目前这个特性还处于 experimental
阶段, 你需要使用
"react": "experimental",
"react-dom": "experimental",
来体验这个特性。如果你使用的是 TypeScript
,你还需要你的 tsconfig.json
中添加以下这段代码
"types": ["react/experimental"]
目前还有一些问题,离稳定还有一段时间。但是我相信在不久的将来,各大路由库、框架、动画库都会支持这个特性。
我们使用的 react
开发的应用会像原生 APP 应用一样,拥有非常丝滑的动画效果。