关于javascript:React如何在React中优雅的实现动画

59次阅读

共计 3693 个字符,预计需要花费 10 分钟才能阅读完成。

最简略的动画组件实现

动画的实质,无非就是一个状态款式到另一个状态款式的过渡。最简略的动画组件,咱们只须要指定两个状态的款式(进入的款式,来到的款式),以及一个开关(管制状态),即可实现。

codepen 地址

实现一组动画的过渡

实现一组动画的过渡。咱们只须要在多个最简略的动画组件的根底之上,设置一个对立的开关,对立管制,多个动画组件动画的状态即可。如果想实现有交织的过渡(有工夫距离的过渡),咱们只须要依据动画组件在一组元素中的索引地位,设置适合的提早即可。

为了引入对立的开关的管制,咱们为动画组件增加一个父级组件,父级组件的开关管制所有子组件的开关状态。父组件应用 React.Context 将本人开关的状态,下发给子组件。

为了实现交织成果,咱们须要为列表中子组件设置不同长度的提早。提早时长和子组件在列表索引,以及开关的状态无关。

比方:

在开关设置为 true, 须要显示入场的动画。提早自上而下,顺次增大(0ms, 100ms, 200ms, 300ms)

在开关设置为 false, 须要显示出场的动画。提早自上而下,顺次减小(300ms, 200ms, 100ms, 0ms)

codepen 地址

上述组件目前存在的问题

  1. 节点必须当时曾经渲染好,对于动静插入的节点,这些动画组件无能为力。(在下方咱们参考了 `react-transition-group 实现解决这个问题)
  2. 如果元素起始款式有 display: none 动画将不会起成果(这个问题其实和动静插入节点属于一类问题)。
  3. 对于一组列表节点。新的节点的插入,和删除时。其余节点的过渡很僵硬,没有动画成果(咱们能够应用 flip 动画解决这个问题)。

FLIP 动画

FLIP 动画实现原理是: 缓存元素终点的地位, 而后将元素置于起点的地位,计算起点与终点的差值,依据差值利用动画。

咱们先看看 flip 动画弱小的成果

接下来,咱们来一步一步实现一个繁难的 flip 动画,而后再尝试在 react 中实现。

闪动

请问上面的代码,会造成闪动的问题吗?

codepen 演示

答案: 是不会。具体起因和浏览器的事件队列无关。点击事件的代码,咱们必须执行实现以后的工作(以后代码段的执行)才会进行浏览器渲染。

这一点对咱们很重要。再重申一遍 flip 动画的原理,缓存元素终点的地位, 而后将元素置于起点的地位,计算起点与终点的差值,依据差值利用动画。

雏形

而后基于下面的代码,咱们目前能够实现一个繁难的 flip 动画

codepen 演示

咱们能够看到,动画曾经实现,然而目前动画的计算还是固定的,咱们接下来尝试让它自动化。

欠缺

咱们尝试对, 之前状态和以后状态的属性, 做主动的差值计算。

codepen 演示

咱们目前曾经实现了,宽度和 x 轴的 flip 动画。

????️为什么要这样计算(之前的地位 – 当初的地位)?

咱们为什么要应用之前的款式值减去以后的款式值?

FLIP 动画的原理是基于以后地位和起始地位的动画,咱们在做动画的时候,元素其实曾经达到了完结的地位。

比方以后的地位是 100px, 开始地位是 0px。flip 动画须要模仿从 0px 到 100px 的过程,然而以后地位曾经是 100px 了,所以咱们必须应用 translateX(0 - 100px), 模仿动画开始时的 0px 的地位。

100ms

There is a window of 100ms after someone interacts with your site where you’re able to do work without them noticing.

应用 flip 动画时,切记计算不能超过 100ms,如果超过 100ms 用户会感到卡顿。

FLIP 与 Web Animations API

目前间隔实现一个真正的 flip 动画库还有不少的间隔。持续应用 requestAnimationFrame 会很艰难,太简单了。

既然 flip 动画,是基于完结地位和开始地位的动画,那么有没有什么好方法,不须要咱们手动的去调整。只须要提供初始地位和完结地位实现动画呢?咱们能够应用 Web Animations API。

对于 Web Animations API 自身,我在这里不想做过多的介绍。大家只须要晓得,应用 Web Animations API 后,咱们只须要设置开始的款式,和完结的款式,动画就会主动实现。

咱们将下面的 demo,革新成应用 Web Animations API 的模式。

codepen 演示

能够看到,咱们在代码里只须要设置开始和完结的款式,动画就会主动过渡实现。

React 与 FLIP

如何在 react 中实现 flip 动画呢?咱们首先回顾下在 js 中 flip 动画的逻辑

  1. 缓存元素起始地位
  2. 将元素挪动到完结的地位
  3. 获取以后的地位,并计算以后的地位与缓存的起始地位的差值。
  4. 下一帧开始时,开始做动画

咱们能够发现,第 1,2,3 步都是产生在渲染到屏幕之前(或者说渲染到屏幕的那一刻)。那么在 react 中,有什么 hook 产生在渲染到页面的那一刻呢?答案是: 函数组件中是useLayoutEffect。class 组件中是componentDidUpdate

咱们整顿下在 react 中 flip 动画的实现逻辑

  1. 在页面第一次 useEffect, 元素渲染实现。这时同时缓存元素的地位。
  2. state 发生变化,组件须要从新渲染
  3. 在组件从新渲染到屏幕那一刻,在 useLayoutEffect 中,咱们获取最新的地位。并计算以后的地位与缓存的起始地位的差值。
  4. 动画开始执行

那么接下来咱们来实现一个 react 中 flip 的雏形

codepen 演示

bigo! 咱们胜利在 react 中实现了 flip 动画

❓ 目前存在的问题

如果咱们在 flip 动画运行过程中,切换动画。动画会呈现闪动,咱们当初来着手解决这个问题。

咱们先来思考一下这个问题产生的起因。动画在运行过程中,还没有达到起点,这时切换动画,动画元素会被强行挪动到起点的地位,而后进行下一次动画,这就是动画闪动的起因。

如何解决呢?

  1. 在切换动画的时候,如果上一次动画没有完结,咱们手动将其完结
  2. 在切换动画的时候,更新地位的缓存。

codepen 演示

尽管目前曾经实现 flip 动画的成果,然而间隔封装成可用的库还有些间隔,如果大家想要理解的更多,能够查看我封装好的源码(原理和下面的文章是截然不同的)。仓库地址: https://github.com/peoplesing…

???? Flip 动画须要留神的点

  1. flip 计算动画地位时,元素上最好不要有 transition 的 css 属性,会影响到地位的计算。
  2. 之前的计算缓存地位时,都是绝对于 body 的地位。然而如果存在有滚动条时,缓存的地位会有问题。解决办法是,基于动画元素的父级元素计算地位,而不是 body 的地位。

Flip 如何实现交织成果?

好吧。目前我的库中,交织成果的欠缺解决方案还没有实现。然而主体思路是有了,并有了繁难的实现版本 见下方????

???????????? 动静插入节点的动画解决

这个问题解决的思路,我参考了 react-transition-group库 的源码。在这里我说一下,react-transition-group库 实现的思路。


<react-transition-group>
  {list && list.map((item) => (
      <react-transition>
        {item}
      </react-transition>
    ))
  }
<react-transition-group>

最外层的 <react-transition-group> 组件 并不会间接对嵌入的 children 进行间接渲染。而是将 props.children 保留为,组件的外部状态 state。这样咱们能够在 children 渲染之前,对 state 做一些额定的操作。

<react-transition-group>会对于动静插入的节点,不会间接渲染。而是先将,新插入节点外层的 <react-transition> 组件的动画状态设置为 ’Leave’ 态(这里解决的目标是,即便 dom 渲染实现后,元素也是暗藏的状态)。而后在 <react-transition> 中,会先期待 dom 渲染实现,而后再将动画的状态设置为 ’Entering’,实现 ’Leave’ 态到 ’Entering’ 态的动画过渡。

<react-transition-group>会对于动静删除的节点,不会间接删除。而是先将须要删除节点外层的 <react-transition> 组件的动画开关设置为 false,动画开始向 ’Leave’ 态过渡。动画过渡实现后,而后会触发 <react-transition> 组件的 onLeave 事件。在 onLeave 事件中会删除 dom 节点。

总结一下 react-transition-group 库的解决形式:

  1. 插入的节点,先渲染 dom,而后再做动画
  2. 删除的节点,先做动画,而后再删除 dom

写在最初

如果您对我的文章感到称心,还请麻烦您给我的文章点一个赞。如果您喜爱我的小我的项目,还请帮我的小我的项目点一个 star。谢谢????

我的项目地址:https://github.com/peoplesing…

参考

  • react-transition-group 源码
  • FLIP Your Animations

正文完
 0