在进行副项目时,我想为用户在路线之间导航时创建漂亮的“ flow” -y动画。路线必须实现不同的“输入”和“离开”动画,具体取决于用户导航到哪个页面和从哪个页面导航,即,从“ 登录”页面导航到“ 首页”时,其动画(“ 登录”页面的离开动画)与“ 登录”动画不同在页面到“ 应用程序”页面。
最后,我得到了一个很整洁的Provider-and-hook二人组,可以与流行的React Router很好地配合使用,所以我想我可以把它打包好并共享。
反应路线转换
因此,反应路线转换是该周末工作的结果。
它的工作方式非常简单。
它导出您需要包装您的应用程序的提供程序(将其放置在react-router的内部Router
)。
在幕后,该Provider只是用Context Provider包装其子级(您的应用程序)。它设置了Context Provider,并为其传递了push(history.push
或push
它们的useHistory
钩子提供的react-router的方法)函数,location(window.location
或react-router的usLocation()
返回值)和(空)侦听器数组。
由react-route-transition(useTransition()
和useTransitionHistory()
)提供的两个钩子将稍后从该上下文读取和写入。
用它包装应用程序后,您可以声明动画的行为。为此,您称为useTransition()
钩子。
描述动画
useTransition()
接受一个对象,该对象的键名为,handlers
其值是Handlers数组。
处理程序是描述以下内容的对象:
- 动画
- 什么时候开火说动画
处理程序对象由以下键组成:
path
-一个字符串(或字符串数组),用于指定动画函数在输入/离开这些路径时应触发的路径。onEnter
-一个异步功能,一旦用户导航到,该功能就会触发path
。这是动画代码所在的位置,应该在完成动画后解析。onLeave
-和一样onEnter
,离开时只会开火path
。
这是使用示例useTransition()
:
useTransition({
handlers: [
{
path: '/',
onEnter: async () => {
await gsap // highlight-line
.timeline() // highlight-line
.fromTo( // highlight-line
'[data-home-main] > *, [data-home-footer]', // highlight-line
{ opacity: 0, y: 20 }, // highlight-line
{ duration: 0.6, stagger: 0.125, y: 0, opacity: 1 } // highlight-line
) // highlight-line
},
onLeave: async () => {
await gsap.timeline().to('[data-home-main] > *, [data-home-footer]', {
duration: 0.6,
stagger: 0.125,
opacity: 0,
y: -20,
})
},
},
],
})
当进入 /
启动的OnEnter动画,当离开,开始onLeave。
当调用useTransition()
卸载的组件时,它注册的处理程序也会被删除,因此不再可见的页面将不会在后台启动动画。
现在,如果您不熟悉gsap,那么它是00年代的老式动画库,仍然非常不错。anime.js是一个不错的轻量级选择。它们都公开了简单的API,使DOM动画变得轻而易举,并且(IMO)比声明性的API更易读(请参见下面的免责声明)。
第一个动画块(突出显示的行)的作用是将数据属性名为的元素home-main
和数据属性名为的元素的所有子项变暗(过渡不透明度为0)home-footer
。每个动画元素将在600毫秒内进行动画处理,并应用125毫秒的惊人效果。
此类动画的渲染元素可能类似于:
return (
<div>
<main data-home-main>{/* this content will be animated */}</main>
<footer data-home-footer>{/* some stuff here as well */}</footer>
</div>
)
等待gsap.timeline().to()
是指等待动画完成(然后它的返回值即可,动画完成后便会解析)。
现在我们准备看动画播放了。
启动动画
当用户导航到(或从中)需要动画的页面时(在上面的示例中,当用户从和进行动画时),react-route-transition将启动动画/
。
使用react-route-transition导航页面的方式与react-router相同,方法是调用history.push("/some-path")
,不同的是history
这里的对象是useTransitionHistory()
由react-route-transition提供的钩子返回的内容。
react-route-transition为您处理导航。它导出名为的钩子useTransitionHistory()
,接受您要导航到的路径。那个钩子精心编排动画。它遍历已注册的处理程序列表,找到哪个描述onLeave
了当前位置的动画,同时启动所有这些动画,等待它们完成,然后调用history.push(反应路由器),这将导致安装新组件并注册其处理程序(可能会或可能不会描述onEnter
此新视图的动画)。最后,它onEnter
为新位置触发所有动画。
2动画1视图
假设您希望onLeave
当用户从“ 登录”页面导航到主页时开始播放一个动画,而当用户从同一“ 登录”页面导航到“ 应用程序”页面时播放一个动画。
您可以通过传递from
和to
选项而不是传递path
选项来实现,例如:
useTransition({
handlers: [
{
from: '/signin',
to: '/app',
onLeave: async () => {
// Animation 1
},
},
{
from: '/signin',
to: '/',
onLeave: async () => {
// Animation 2
},
},
],
})
留给何时开始动画1 应用程序页面,动画2留给当主页页面。
最后,path
,from
和to
也接受的路径的阵列。当您想要导航到(或从)多个页面时触发相同的动画时,这很有用。
为什么需要命令式动画?
就个人而言,我不喜欢以声明性的方式编写复杂的动画。它们非常适合交互,但是我发现与以命令方式编写的动画相比,学习曲线陡峭,代码可读性受到影响,玩转(只是测试内容)不如反馈循环会更长。那可能是因为我是作为Flash(ActionScript)开发人员开始的,因为补间动画非常流行,因此不要以为事实。如果您喜欢采用声明式方法,请在下面的评论中让我知道,我很想听听他们的优点!