- 原文地址:A gentle introduction to React Motion
- 原文作者:Nash Vail
- 译文出自:掘金翻译计划
- 本文永久链接:github.com/xitu/gold-m…
- 译者:doctype233
- 校对者:
React 很棒,在过去的几周里,我用它玩得很开心,所以我决定尝试一下React Motion。一开始 API 就让我感到有困惑和棘手,但是最终一切开始变得有意义,不过这需要时间。遗憾的是,我在网上找不到合适的 React Motion 教程,所以我决定把这篇文章写出来,不仅是作为一个开发者们的资源,也能给我自己作参考。
React Motion 对外暴露三个主要的组件:Motion, StaggeredMotion 和 TransitionMotion。在本教程中,我们将一起看一看 Motion 组件,之后你会发现将在这一部分花费大量时间。
由于这是一个 React Motion 教程,所以我将假设你有点熟悉 React 以及 ES2015。
我们将在使用 React Motion 重新创建 一个 Framerjs 的例子 时探索 API。你可以在这找到代码的最终版本 在这。
最终效果
我们首先要研究一点数学问题,但是不要担心,我会尽可能详细地解释每一个步骤。你可以直接跳过这一部分到 React.start(); 部分。
准备好了吗? 那就开始吧...
Math.start();
我们可以把蓝色的大按钮称为——主按钮, 从蓝色按钮上飞出的按钮称为——子按钮。
Fig. 1
子按钮拥有两种位置状态, 1) 子按钮均隐藏在主按钮后面的位置, 2) 子按钮在主按钮周围排列成一个圆圈的位置。
这里就出现了数学问题,我们必须想出一种方法,在一个完美的圆中均匀地排列主按钮周围的子按钮。你可以通过试错法将这些值通过代码写死,但认真的说,谁会这么做呢?另外,一旦你找到正确的数学方法,只要你愿意你可以摆放任意多的子按钮,而他们都会自动排列自己。
首先让我们了解几个术语。
M_X, M_Y
Fig. 2
M_X, M_Y 分别表示以主按钮为中心的 X 和 Y 坐标。(M_X, M_Y) 这个点将用作计算每个子按钮的距离和方向的参考。
每个子按钮最初都隐藏在主按钮中心的后面,中心坐标为 M_X, M_Y。
分离角、扇形角、飞出半径
Fig. 3
飞出半径为子按钮飞出后距离主按钮的距离,其他两个词语的释义看起来不言自明。
还需要注意一个地方,
扇形角 = (子按钮数-1) * 分离角
现在,我们需要设计一个函数,该函数接收子按钮 (0, 1, 2, 3 …) 的索引,并返回子按钮的新位置的 x 和 y 的坐标。
基准角、索引
Fig. 4
由于通常来说三角学中的角度是从 x 轴的正方向测量的,我们将从相反的方向(右到左)开始给我们的子按钮编号。这样,以后我们就不必在每次需要子按钮的最后位置时乘以负一。
当我们看到它时,请注意 (参见 Fig. 3)
基准角 = (180 — 扇形角)/2
(一定程度上)。
角
Fig. 5
每个子按钮都有它自己的角度,我称之为角。这个角是计算子按钮最终位置所需的最后一条信息。
请注意, (参见 Fig. 3, Fig. 4)
索引为 i 的子按钮的角度 = 基准角 + ( i * 分离角)
现在,一旦我们有了每个子按钮的角,
Fig. 6
我们就能够为每个子按钮计算 增量X and 增量Y。
请注意 (参见 Fig. 2),
子按钮的最终 X 轴坐标 = M_X + 增量X
子按钮的最终 Y 轴坐标 = M_Y - 增量Y
(我们从 M_Y 中减去增量X,因为不同于原点在左下角的一般坐标系,浏览器的原点在左上角,所以为了方便移动,你可以降低他们 y 轴坐标的值。)
所以,这些就是我们所需要的数学方法,现在我们有两样东西:每个子按钮的初始位置 (M_X, M_Y) 和子按钮的最终位置,剩下的魔发就交由 React 来完成吧!
React.start();
在下面的关键代码中,你将会看到发生什么,点击主按钮,我们将 isOpen 的状态变量设置为 true (第85行)。一旦 isOpen 为 true,就会传递不同的子按钮的样式(第97行,第66行,第75行)。
结果:
Fig. 7
好的,我们在此处完成了很多操作,我们在按钮上设置子按钮的初始位置和最终位置,现在我们需要做的就是添加 React Motion 来激活在初始位置和最终位置之间的动画。
React-Motion.start();
获取 几个参数 每个参数是可选的,但我们不关心这里的可选参数,因为我们没有做任何与这个参数有关的事情。
其中 一个参数是 style, style 将作为参数传递到回调函数中,该函数包含内建的 interpolated values ,然后执行它的动画。
(第8行 : 因为正在React中执行迭代,所以需要将一个 key 参数传递给子组件。)
就像这样,
即使在这样做以后,结果也不会与图 Fig. 7 有所不同,为什么这么说?好吧,我们还需要最后一步,使用_spring_。
正如前面提到的, 回调函数包含内建的值,也就是说, spring 帮助函数内建的值插入样式值。
我们需要修改 initialChildButtonStyles 和 finalChildButtonStyles 并注意 top 和 left 被 spring 覆盖的值。这些是仅有的改变,现在,
Fig. 8
spring 可选地接收第二个参数,这是一个包含两个数字的数组 [Stiffness, damping],默认值为[170,26],这导致了上图 Fig. 8 中呈现的结果。
将 Stiffness 视为动画发生的速度,这不是一个非常精确的假设,只是速度越大的值越大。Dampness 是一个晃动效果参数,不过相反的,值越小,晃动效果越明显。
可以看看这个
[320, 8] — Fig. 9
[320, 17] — Fig. 10
我们离最终完成很近了,但是还没有。如果我们在每次下一个子按钮开始动画前添加延迟会怎样?为了达到最终效果,这正是我们需要做的,但这样做并不那么简单,我不得不把每个运动组件以数组的形式存储到状态变量中,然后一个一个地为每个子按钮改变状态以达到期望的效果,代码就像这样
this.state = {
isOpen: false,
childButtons: []
};
复制代码
然后在 componentDidMount 方法中添加 childButtons
componentDidMount() {
let childButtons = [];
range(NUM_CHILDREN).forEach(index => {
childButtons.push(this.renderChildButton(index));
});
this.setState({childButtons: childButtons.slice(0)});
}
复制代码
最终打开菜单功能得以实现:
我们在这里做了一些美学的调整,如添加图标和一些旋转效果,我们得到最终效果如下。
方法已覆盖,你可以设置任何数量的子按钮
NUM_CHILDREN = 1
NUM_CHILDREN = 3
NUM_CHILDREN = 8
相当酷对吗? 再说一遍,你可以 在这找到相应代码。如果你觉得这篇文章有帮助,请点击下面的推荐按钮。
如果有一些问题、评论、建议或仅仅是想聊个天?可以在 Twitter 上找到我 @NashVail 或者给我发电子邮件 hello@nashvail.me。
你可能还会喜欢
如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。