上一篇博客讲了React官方提供的TransitionGroup
动画库,它实现的原理是典型的CC3
方式,现在再来了解一下如何使用脚本的方式
来实现动画。要使用脚本的方式实现动,我们可以采用react-motion
这个动画库,它是一个很优秀的动画库,并且采用的是脚本的方式
来实现动画。(motion是运动的意思)
react-motion : https://github.com/chenglou/react-motion
1.安装react-motion动画库
yarn add react-motion
//ro
npm install react-motion
2.计数器案例
该案例实现由数字 0 加到 1
1.从react-motion库中导入 spring 和 Motion
spring : 指定如何为目标值设置动画,例如,spring(10, {stiffness: 120, damping: 17})
表示“动 画到数值10,弹簧刚度为120,阻尼为17”
Motion : 它是一个专门提供动画数据的组件,它接收一个函数作为子组件, 例如:
< motion >
{ value => ( ) }
</ Motion >
2.Motion组件属性:
defaultStyle : 设置动画开始前默认数值
style : 设置动画要到数值
import React, {Component} from 'react';
import {spring ,Motion} from 'react-motion';
export default class Main extends Component {
render() {
return (
<div style={styles.content}>
{/*由0 过渡到 1 ; stiffness是阻尼*/}
<Motion defaultStyle={{x: 0}} style={{x: spring(1,{stiffness: 20})}}>
{
value =>
<div>
{value.x}
</div>
}
</Motion>
</div>
)
}
}
/*样式*/
const styles = {
content: {
width: '400px',
height: '500px',
backgroundColor: 'skyblue',
margin: '0 auto',
},
}
执行的效果:
2.改变透明度和宽的动画案例
通过上面的案例可以知道 Motion 组是专门提供动画数据的
,其实它并没有参与界面的绘制,界面的绘制过程是通过子组件来完成的
。下面我们来做一个改变透明度和宽的动画案例
1.从react-motion
库中导入 spring 和 Motion
2.value.x
的值是由0过渡到1
的, 可以通过Motion提供的这个动画数据类修改div的 透明度和宽度
3.${value.x}
两边添加了反引号
,这个是es6中的字符串模板语法。${} 可以理解为插值器
import React, {Component} from 'react';
import {spring ,Motion} from 'react-motion';
export default class Main extends Component {
render() {
return (
<div style={styles.content}>
{/*由0 过渡到 1 ; stiffness是阻尼*/}
......
{/*改变div的宽度和透明度*/}
<Motion defaultStyle={{x: 0}} style={{x: spring(1,{stiffness: 20})}}>
{
value =>
<div style={ Object.assign({},styles.divStyle,{
opacity:`${value.x}`,
width:`${50+value.x*100}px`
})}>
默认
</div>
}
</Motion>
</div>
)
}
}
/*样式*/
const styles = {
content: {
....
},
divStyle: {
width: '50px',
height: '50px',
backgroundColor: 'green',
margin: '3px 0',
color:'white'
},
}
刷新界面执行到0.2的效果:
执行结束后的结果:
3.TransitionMotion执行装载和卸载动画案例
之前学的TransitionGroup
动画库提供了执行组件的装载和御载的动画。其实react-motion
也提供了这个功能,要使用这个功能就要用到一个新的API : TransitionMotion
组件,该组件可以帮助您执行组件的装载和卸载动画。
1.从react-motion
库中导入 TransitionMotion, spring 和 presets
TransitionMotion 是执行组件的装载和卸载动画
spring : 指定如何为目标值设置动画
presets : 预设设刚度和阻尼的值
2.添加组件时:状态由willEnter()中定义的状态过渡到styles中定义的状态
willEnter(){
return {width: 0, height: 0};
}
// 由willEnter()中width: 0, height: 0状态过渡到下面styles中width:200, height: 50状态
// spring() 函数为目标值设置动画
// presets.wobbly 等价于 {stiffness: 180, damping: 12}
styles={this.state.items.map(item => ({
key: item.key,
style: {width: spring(item.w,presets.wobbly), height: spring(50,presets.wobbly)},
}))}
3.删除组件时:状态由styles中定义的状态过渡到willLeave中定义的状态
styles={this.state.items.map(item => ({
key: item.key,
style: {width: spring(item.w,presets.wobbly), height: spring(50,presets.wobbly)},
}))}
// 由styles中width:200, height: 50状态过渡到下面willEnter()中width: 0, height: 0 状态
// presets.wobbly 等价于 {stiffness: 180, damping: 12}
//下面的 spring(0,presets.wobbly) 设置目标值动画
willLeave() {
return {width: spring(0,presets.wobbly), height: spring(0,presets.wobbly)};
}
案例完整的代码:
import React, {Component} from 'react';
import {TransitionMotion,spring , presets} from 'react-motion';
export default class Main extends Component {
constructor(props) {
super(props);
/*定义一个数组:目标状态*/
this.state={
items: [{key: 'a', w: 200},{key: 'b', w: 200}],
}
}
/*装载组件的状态( 进入/添加组件 )*/
willEnter(){
return {width: 0, height: 0};
}
/*御载组件的状态( 离开/删除组件 )*/
willLeave() {
return {width: spring(0,presets.wobbly), height: spring(0,presets.wobbly)};
}
render() {
return (
<div style={styles.content}>
<TransitionMotion
willEnter={this.willEnter}
willLeave={this.willLeave}
styles={this.state.items.map(item => ({
key: item.key,
style: {width: spring(item.w,presets.wobbly), height: spring(50,presets.wobbly)},
}))}>
{interpolatedStyles =>
<div>
{interpolatedStyles.map(config => {
return <div key={config.key} style={{...config.style, border: '1px solid'}} >
{config.key} : {config.style.height}
</div>
})}
</div>
}
</TransitionMotion>
<button onClick={()=>this.startAnimation(0)}>Add C</button>
<button onClick={()=>this.startAnimation(1)}>remove C</button>
</div>
)
}
startAnimation(index){
// add
if(index==0){
this.setState({
items: [{key: 'a', w: 200},{key: 'b', w: 200},{key: 'c', w: 200}],
})
// remove
}else{
this.setState({
items: [{key: 'a', w: 200},{key: 'b', w: 200}],
})
}
}
}
/*样式*/
const styles = {
content: {
width: '400px',
height: '500px',
backgroundColor: 'skyblue',
margin: '0 auto',
},
}
刷新浏览器默认的状态:
点击 Add C 后,添加一个div, 宽和高在慢慢的变大