userSpring
两种方式创建
通过函数和依赖的方式
import { useSpring, animated } from '@react-spring/web'
function MyComponent() {
const [props, api] = useSpring(
() => ({
from: { opacity: 0 },
to: { opacity: 1 },
}),
[]
)
return <animated.div style={props}>Hello World</animated.div>
}
很明显,这种是通过方法的方式,返回参数的SpringValue
对象和API
对象
通过配置对象的方式
import { useSpring, animated } from '@react-spring/web'
function MyComponent() {
const props = useSpring({
from: { opacity: 0 },
to: { opacity: 1 },
})
return <animated.div style={props}>Hello World</animated.div>
}
参数说明
Prop | Type | Default | |||
---|---|---|---|---|---|
from | object | – | |||
to | object | object[] | function | – | |
loop | boolean | object | function | – | |
delay | number | function | – | ||
immediate | boolean | function | – | ||
reset | boolean | – | |||
reverse | boolean | – | |||
pause | boolean | – | |||
cancel | boolean | string | string[] | function | – |
ref | SpringRef | – | |||
config | object | function | object | ||
events | function | – |
useSprings
如果你想要不用定义API
串联多个spring
,这个hook
很适合你的想法。
可以把useSprings
看成useSpring
的组合,例如:
通过函数和依赖的方式
import { useSprings, animated } from '@react-spring/web'
function MyComponent() {
const [springs, api] = useSprings(
2,
() => ({
from: { opacity: 0 },
to: { opacity: 1 },
}),
[]
)
return (
<div>
{springs.map(props => (
<animated.div style={props}>Hello World</animated.div>
))}
</div>
)
}
通过配置对象的方式
import { useSprings, animated } from '@react-spring/web'
function MyComponent() {
const springs = useSprings(2, {
from: { opacity: 0 },
to: { opacity: 1 },
})
return (
<div>
{springs.map(props => (
<animated.div style={props}>Hello World</animated.div>
))}
</div>
)
}
参数和useSpring
相同
useSpringValue
这个hooks
满足的场景就是一些简单的属性改变,比如某一个字体,背景颜色,就可以直接用useSpringValue
初始化一个对象,而这个对象就是某个类型的SpringVale
的对象。
值的方式初始化
例如想要改变div
样式中的透明度,则可以用number
的值初始化对象
import { useSpringValue, animated } from '@react-spring/web'
function MyComponent() {
const opacity = useSpringValue(0)
return <animated.div style={{ opacity }}>Hello World</animated.div>
}
动画属性的配置
import { useSpringValue, animated } from '@react-spring/web'
function MyComponent() {
const opacity = useSpringValue(0, {
config: {
mass: 2,
friction: 5,
tension: 80,
},
})
return <animated.div style={{ opacity }}>Hello World</animated.div>
}
动画执行
import { useSpringValue, animated } from '@react-spring/web'
function MyComponent() {
const opacity = useSpringValue(0, {
config: {
mass: 2,
friction: 5,
tension: 80,
},
})
const handleClick = () => opacity.start(1)
return (
<animated.div onClick={handleClick} style={{ opacity }}>
Hello World
</animated.div>
)
}
参数
Prop | Type | Default | |||
---|---|---|---|---|---|
to | object | object[] | function | – | |
loop | boolean | object | function | – | |
delay | number | function | – | ||
immediate | boolean | function | – | ||
reset | boolean | – | |||
reverse | boolean | – | |||
pause | boolean | – | |||
cancel | boolean | string | string[] | function | – |
config | object | function | object | ||
events | function | – |
useTransition
可以把这个当作过渡动画,一般主要用视图的的淡入淡出动画,例如弹窗页面。useTransition
依赖于一个数组对象data
,data
对象中元组类型是自定义的,我们使用了方法去追踪data
中数据包括引用的key
,这是函数第一个参数,第二个是配置对象,这儿参数和之前useSpring
或者useSprings
中有所不同,所以这儿需要注意!
通过函数和依赖方式初始化
import { useTransition, animated } from '@react-spring/web'
function MyComponent({ data = [1, 2, 3] }) {
const [transitions, api] = useTransition(data, () => ({
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 1 },
}))
return transitions((style, item) => (
<animated.div style={style}>{item}</animated.div>
))
}
通过配置对象方式初始化
import { useTransition, animated } from '@react-spring/web'
function MyComponent({ data = [1, 2, 3] }) {
const transitions = useTransition(data, {
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 1 },
})
return transitions((style, item) => (
<animated.div style={style}>{item}</animated.div>
))
}
从上面的例子可以看到,在dom
标签中,transitions
中每轮巡一次就会生成一个div
,而每个div
需要一个key
标识,然后方法返回的参数中style
就是把动画和对象的属性相关联,当动画到了enter
阶段,则会取你配置中的对象进行动画,其中的item
就是数组对象的元组,是自定义对象的。
参数
Prop | Type | Default | |||
---|---|---|---|---|---|
from | object | function | – | ||
intial | object | function | – | ||
enter | object | object[] | function | – | |
update | object | object[] | function | – | |
leave | object | object[] | function | – | |
keys | Array<string | number> | function | null | – |
sort | function | – | |||
trail | number | 0 | |||
exitBeforeEnter | boolean | false | |||
expires | boolean | number | function | true | |
ref | SpringRef | – | |||
config | object | function | object | ||
events | function | – |
useChain
useChain
可以用来像珠子样串联一个又一个动画,那么这个就可以满足你想要把不同类型的动画串联起来的需要,例如上面的useSpring
和useTransition
类型的动画。
用法
先运行数组参数中的第一个动画,接着是第二个动画,当第二个动画在运行的时候,第一个就会休息。
例如:
import { useTransition, useSpring, useChain, animated, useSpringRef, } from '@react-spring/web'
const data = ['hi', 'there!']
function MyComponent() {
const springRef = useSpringRef()
const springs = useSpring({
ref: springRef,
from: { size: '20%' },
to: { size: '50%' },
})
const transRef = useSpringRef()
const transitions = useTransition(data, {
ref: transRef,
from: { scale: 0 },
enter: { scale: 1 },
leave: { scale: 0 },
})
useChain([springRef, transRef])
return (
<animated.div
style={{
height: springs.size,
width: springs.size,
background: 'blue',
}}>
{transitions((style, item) => (
<animated.div
style={{
width: '120px',
height: '120px',
background: 'green',
...style,
}}>
{item}
</animated.div>
))}
</animated.div>
)
}
时间间隔
通过上面的举例我们可以看到在useSpring
函数休息后执行useTransition
函数,这个是useChain
函数特定的一个机制。
但是,有的时候你想要去控制不同动画之间的间隔时间的时候,那么你可以这样做。
useChain([springRef, transRef], [0, 1], 1000)
新增的两个参数中,第一个时间的步长,这个参数中的元素的值必须是0-1之间的,第二个参数是时间基数长度(默认是1000ms),这两个参数的详细含义可看下面代码
const refs = [springRef, transRef]
const timesteps = [0, 1]
const timeframe = 1000
refs.forEach((ref, index) => {
const time = timesteps[index] * timeframe
ref.delay = time
})
第一个数组中对应的动画和第二个时间基数的乘积就是当前动画需要延时执行的时间。
所以,如果你想要你的第二个动画延迟400ms
执行,可以
useChain([springRef, transRef], [0, 0.4])
相关代码
function useChain(refs: ReadonlyArray<SpringRef>): void
function useChain(refs: ReadonlyArray<SpringRef>, timeSteps: number[]): void
function useChain(
refs: ReadonlyArray<SpringRef>,
timeSteps: number[],
timeFrame: number
): void
useTrail
useTrail
在函数的写法上和之前的useSprings
相同,但不同的是useTrail
中动画的开始执行是紧接着上一个的完成时。而useSprings
在视觉上表现出来的效果是同时的出现。
通过函数和依赖的方式
import { useTrail, animated } from '@react-spring/web'
export default function MyComponent() {
const [trails, api] = useTrail(
2,
() => ({
from: { opacity: 0 },
to: { opacity: 1 },
}),
[]
)
return (
<div>
{trails.map(props => (
<animated.div style={props}>Hello World</animated.div>
))}
</div>
)
}
通过配置对象的方式
import { useTrail, animated } from '@react-spring/web'
export default function MyComponent() {
const trails = useTrail(2, {
from: { opacity: 0 },
to: { opacity: 1 },
})
return (
<div>
{trails.map(props => (
<animated.div style={props}>Hello World</animated.div>
))}
</div>
)
}
Parallax
需要和ParallaxLayer
组件共同使用,简洁而可声明地创建视觉上的可滑动效果视图。
用法
注意:
这个组件只能在@react-spring/web
包中可用并且只支持浏览器上。
Parallax
组件创建了一个可滑动的容器,这个容器可以放置ParallaxLayer
,而react.Fragment
在ParallaxLayer
中直接的使用。因为Parallax
是一个包含所有可滑动事件的容器,你会发现,在window
上监听滑动事件是不行的,所以,如果你要在上面添加别的事件,你可以使用ref.current.container
。
import { Parallax, ParallaxLayer } from '@react-spring/parallax'
function MyComponent() {
return (
<Parallax pages={1} style={{ top: '0', left: '0' }}>
<ParallaxLayer offset={0} speed={2.5}>
<p>Parallax</p>
</ParallaxLayer>
</Parallax>
)
}
参数
所有的参数可以传递给HTMLDivElement
也可以传递给Parallax
Prop | Type | Default | |
---|---|---|---|
pages | number | – | |
config | object | function | object |
enabled | boolean | true | |
horizontal | boolean | false | |
innerStyle | CSSProperties | – |
Ref
通过ref
参数给到Parallax
组件,这样在外部你就可以通过ref.current
去获取Parallax
组件。
interface IParallax {
config: ConfigProp
horizontal: boolean
busy: boolean
space: number
offset: number
current: number
controller: Controller<{ scroll: number }>
layers: Set<IParallaxLayer>
container: React.MutableRefObject<any>
content: React.MutableRefObject<any>
scrollTo(offset: number): void
update(): void
stop(): void
}
Parallax Layer
interface IParallaxLayer {
horizontal: boolean
sticky: StickyConfig
isSticky: boolean
setHeight(height: number, immediate?: boolean): void
setPosition(height: number, scrollTop: number, immediate?: boolean): void
}
type StickyConfig = { start?: number; end?: number } | undefined