react-spring -- hooks

786 阅读6分钟

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> 
}

参数说明

PropTypeDefault
fromobject
toobjectobject[]function
loopbooleanobjectfunction
delaynumberfunction
immediatebooleanfunction
resetboolean
reverseboolean
pauseboolean
cancelbooleanstringstring[]function
refSpringRef
configobjectfunctionobject
eventsfunction

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>
	)
}

参数

PropTypeDefault
toobjectobject[]function
loopbooleanobjectfunction
delaynumberfunction
immediatebooleanfunction
resetboolean
reverseboolean
pauseboolean
cancelbooleanstringstring[]function
configobjectfunctionobject
eventsfunction

useTransition

可以把这个当作过渡动画,一般主要用视图的的淡入淡出动画,例如弹窗页面。useTransition依赖于一个数组对象datadata对象中元组类型是自定义的,我们使用了方法去追踪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就是数组对象的元组,是自定义对象的。

参数

PropTypeDefault
fromobjectfunction
intialobjectfunction
enterobjectobject[]function
updateobjectobject[]function
leaveobjectobject[]function
keysArray<stringnumber>functionnull
sortfunction
trailnumber0
exitBeforeEnterbooleanfalse
expiresbooleannumberfunctiontrue
refSpringRef
configobjectfunctionobject
eventsfunction

useChain

useChain可以用来像珠子样串联一个又一个动画,那么这个就可以满足你想要把不同类型的动画串联起来的需要,例如上面的useSpringuseTransition类型的动画。

用法

先运行数组参数中的第一个动画,接着是第二个动画,当第二个动画在运行的时候,第一个就会休息。

例如:

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.FragmentParallaxLayer中直接的使用。因为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

PropTypeDefault
pagesnumber
configobjectfunctionobject
enabledbooleantrue
horizontalbooleanfalse
innerStyleCSSProperties

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