动画
动画的作用并不是核心功能, 但是能够提高用户体验
动画的实现方式
CSS方式
通过CSS的transition方式来渲染动画, 运行效率比脚本方式高, 浏览器原生支持, 不会造成JavaScript的解释执行负担
不过:
- 动作规则的定义是基于时间和速度曲线的, 可能不利于动画的流畅
- 动画随着用户的操作, 可能会被打断
- 动画效果难以进行调试
脚本方式
脚本方式最大的好处是提供了更强的灵活性, 开发者可以任意控制动画效果
缺点是:
- 消耗的计算资源更多
requestAnimationFrame 不是以固定的16ms间隔去渲染, 而是通过脚本给他传入一个回调函数, 浏览器来决定何时调用, 并根据逝去的时间来决定界面的渲染状态 16ms : 保证每秒60帧, 以达到流畅的动画效果
ReactCSSTransitionGroup
需要借助react-addons-css-transition-group这个库
$ yarn add react-addons-css-transition-group
接着引入这个库:
import TransitionGroup from 'react-addons-css-transition-group'
TransitionGroup的主要工作是帮助我们在装载和卸载的时候处理动画过程
使用它来包裹我们的todoList组件渲染结果:
return (
<ul className="row list-group">
<TransitionGroup transitionName="fade" transitionEnterTimeout={500}
transitionLeaveTimeout={200} >
{
todos.map(todo => (
<TodoItem
id={todo.id}
key={todo.id}
text={todo.text}
completed={todo.completed}
/>
))
}
</TransitionGroup>
</ul>
)
- transitionName指定了CSS类的前缀规则
.fade-enter {
opacity: .01;
}
.fade-enter.fade-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.fade-leave {
opacity: 1;
}
.fade-leave.fade-leave-active {
opacity: .01;
transition: opacity 200ms ease-in;
}
ReactTransitionGroup规则
ReactTransitionGroup依赖于CSS, 它的作用是让React组件在生命周期的特定阶段使用不同的CSS规则
类名规则
- transitionName 是所有css类名的统一前缀
- enter 代表装载
- leave 代表卸载
- active 代表动画结束时的状态
在加载动画的时候, 并不是一次装载的:
- 首先装载-enter类
- 在下一个时钟周期才装载-enter-active的类
- leave的过程类似
动画时间长度
动画的持续时间在两个地方都要指定, 第一个是在组件声明上, 第二个是在transition-duration上指定, 两个时间一般是一致的
- 组件上指定的时间是active类的存在时间
- css中的时间是实际的动画时间
加入两者不一致, 前者小于后者, 会在第一个时间到达时移除active类, 导致动画突变, 直接到达最终结果
装载时机
TransitionGroup要发挥作用, 必须自身已经装载完成
也就是说, TransitionGroup必须在目标组件之外装载, 这样才能够使动画生效
首次装载
如果已经存在了若干TodoItem组件实例, 这些组件是不会有动画效果的, 因为enter过程不包括首次装载, 只包括装载完成之后新加入的组件
如果想让首次装载也存在动画效果, 就要使用appear过程, 即-appear和-appear-action为后缀的样式
appear有一点特殊, 通常来说首次装载是不需要动画的, 所以默认控制动画的开关是关闭的
var defaultProps = {
transitionAppear: false,
transitionEnter: true,
transitionLeave: true
};
React-Motion动画库
React-Motion使用的是脚本方式来实现动画
设计原则
- 大部分情况下, 友好的API比性能更重要
- 不要以时间和速度曲线来定义动画, React-Motion使用了两个参数来定义动画: 刚度和阻尼
在React-Motion中大量的使用了函数作为子组件的模式
$ yarn add react-motion
<Motion defaultStyle=
style={
{ x: spring(0, { stiffness: 100, damping: 100 }) }
} >
{value => <div>{Math.ceil(value.x)}</div>}
</Motion>
- defaultStyle 指定了初始值
- style 指定了目标值
- 通过stiffness和damping定义了节奏
- 期间不断调用子函数, 完成动画过程
Motion内部使用requestAnimationFrame来出发, 具体的绘制是由子组件来完成