首页 > 其他分享 >使用React动画库——react-spring

使用React动画库——react-spring

时间:2023-01-06 11:01:44浏览次数:54  
标签:react 动画 spring ctx React props

使用React动画库——react-spring

虚拟JIP属地: 浙江 0.722019.11.08 16:28:04字数 644阅读 16,174

为了让后台系统视觉体验更好,决定增加过渡动画效果。
React官网中提到的动画库有3个:React Transition GroupReact Motion 以及 React Spring。·
我选择用react-spring的原因,无非就是文档是3个中看的最顺眼的,所以就选它了。

react-spring 是一个基于弹簧物理学的动画库,满足大多数与UI相关的动画需求,提供了足够灵活的工具,可以自信地将想法投射到不断变化的界面中。
该库代表了一种现代动画方法。它的灵感很大程度上来自克里斯托弗·切多(Christopher Chedeau)的 animated 和成娄(Cheng Lou)的 react-motion 。它继承了animated强大的插值和性能,以及react-motion的易用性。
虽然animated主要是命令式的,而react-motion主要是声明式的,但react-spring却在两者之间架起了桥梁。

react-spring库提供了2种API,一种是 Hooks api(就是 React 16.8 的新增特性——Hook),一种是 Render-props api。

下面是我加到系统后台的过渡动画(以后增加再写出来慢慢补充):

当值改变时,数字的过渡动画:
// 用 Hooks api 写的话,就是重新写一个函数组件
 import { useSpring, animated } from 'react-spring'
 function Number(props) {
  const props = useSpring({ number: props.number ? props.number : 0 });
   return (
     <animated.span>
      {props.number.interpolate(x => (x * 100).toFixed(0))}
     </animated.span>
   )
 }
// 如果要再已有的Class组件内直接加的话,用 Render-props api
import { Spring, animated } from 'react-spring/renderprops'
 <Spring native to={{ number: classWrongScore ? classWrongScore : 0 }}>
   {props => (<animated.span>
           {props.number.interpolate(x => (x * 100).toFixed(0))}
        </animated.span>)}
 </Spring>
当值改变时,环形图的过渡动画:

下面的是从我之前用css写的环形图改过来的。

import { Spring, animated } from 'react-spring/renderprops'

 <div className={style.annulusBasics}>
     <div className={style.centerCircle}></div>
     <div className={style.annulusOuter}></div>
     <Spring native to={{ number: classWrongScore ? classWrongScore : 0 }}>
      {props => <>
        <animated.div className={style.leftRectangle} style={{
            transform: props.number.interpolate(x => (x > 0.5 ? `rotate(${180 * x}deg)` : 'rotate(0deg)'))
        }}></animated.div>
        <animated.div className={style.rightRectangle} style={{
            transform: props.number.interpolate(x => (x <= 0.5 ? `rotate(${360 * x}deg)` : 'rotate(0deg)')),
            background: props.number.interpolate(x => (x > 0.5 ? '#FF7F69' : '#EDEDED'))
        }} ></animated.div>
        </>}
     </Spring>
     {/* 加下面一个div是因为hidde在移动端失效导致样式不对 */}
     <div className={style.repairAnnulus}></div>
  </div>

下面的是从我用canvas写的环形图demo改过来的,我是写成函数组件的形式。

import React, { useEffect } from "react";

export default function canvasDonut(props) {
    useEffect(() => {
        const ctx = document.getElementById("myCanvas").getContext("2d");
        //外圆环
        ctx.beginPath();
        ctx.arc(50, 50, 47, 0, 2 * Math.PI);
        ctx.lineWidth = 1;
        ctx.strokeStyle = "#fff";
        ctx.fillStyle = "#EDEDED";
        ctx.fill();
        ctx.stroke();
        //内圆环
        ctx.beginPath();
        ctx.arc(50, 50, 35, 0, 2 * Math.PI);
        ctx.lineWidth = 1;
        ctx.strokeStyle = "#fff";
        ctx.fillStyle = "#fff";
        ctx.fill();
        ctx.stroke();
        // //圆环图的进度条
        ctx.beginPath();
        ctx.arc(50, 50, 41, -Math.PI / 2, -Math.PI / 2 + props.percent * (Math.PI * 2), false);
        ctx.lineWidth = props.percent!==0 && 12;
        ctx.lineCap = "round";
        ctx.strokeStyle = "rgb(255, 127, 105)";
        ctx.stroke();
    });
    return (
        <canvas id="myCanvas" width="100" height="100" />
    );
}
<Spring to={{ number: classWrongScore ? classWrongScore : 0 }}>
     {props => <CanvasDonut percent={props.number}/>}
</Spring>
定时上下滚动:
//定时上下滚动
function useTimingRolling(time = 1000, distance) {
    const [scrolling, setScrolling] = useSpring(() => ({ from: { scroll: 0 } }))
    const ref = useRef(null)
    useEffect(() => {
        if (!distance) { distance = ref.current.clientHeight }
    }, [])
    useEffect(() => {
        let intervalID = setInterval(() => {
            setScrolling({ scroll: ref.current.scrollTop + distance });
            if (Math.ceil(ref.current.scrollTop + ref.current.clientHeight) >= ref.current.scrollHeight) {
                setScrolling({ scroll: 0 });
            }
        }, time);
        return () => { clearInterval(intervalID); }
    }, [])
    return [scrolling.scroll, ref]
}

function chestnut() {
    const [timeTable, timeTableRef] = useTimingRolling(10000);
    return (
        <animated.div scrollTop={timeTable} ref={timeTableRef} >
            {new Array(10).fill('chestnut').map((item, i) => (
                <animated.div key={i}> {item}{i} </animated.div>
            ))}
        </animated.div>
    )
}
逐条滚动:
function chestnut() {

    const [delayTable, setDelayTable] = useState(new Array(10).fill('chestnut'))
    useEffect(() => {
        let intervalID;
        intervalID = setInterval(() => {
            new Promise(resolve => {
                let ago;
                setDelayTable(delayTable => { ago = delayTable.shift(); return delayTable })
                resolve(ago)
            }).then((res) => {
                setDelayTable(delayTable => { delayTable.push(res); return delayTable })
            })
        }, 5000)
        return () => { clearInterval(intervalID); clearTimeout(dingshi) }
    }, [])

    const transitions = useTransition(delayTable, (item, i) => i, {
        from: { transform: 'rotateX(0deg)' },
        enter: { transform: 'rotateX(0deg)' },
        leave: { transform: 'rotateX(90deg)' },
    })

    return (
        <animated.div>
            {transitions.map(({ item, props, key }) =>
                <animated.div style={props} key={key}>
                    <animated.span>{item}{i}</animated.span>
                </animated.div>
            )}
        </animated.div>
    )
}

使用 Hooks api注意点:

  • Hooks api 中的 useSpring 只能写在函数组件中,写在Class组件中会报错。

使用 Render-props api 注意点:(renderprops是:Spring,Transition,Trail,Keyframes,Parallax)

  • 如果需要使用 interpolate插值的话,需要在 renderprops 中加一个 native 标志,不然会报错。
  • 如果在 renderprops 加一个 native 标志,接收元素需要变成 animated.[elementName],(例如div变为animated.div),不然会报错。

这个库在打包的时候可能会有个坑:
我是用roadhog,所以使用了这个库之后编译打包,会报错 Failed to minify the bundle. Error: 2.async.js from UglifyJs。原因是这个 npm 包没有遵守约定,没有转成 es5 就发上去,可以看下这个文章
解决方案就是可以在.webpackrc里加入以下代码,让 babel 编译 node_modules 下指定的文件

{
  "extraBabelIncludes": [
    "node_modules/react-spring",
  ]
}
    8人点赞   React    

标签:react,动画,spring,ctx,React,props
From: https://www.cnblogs.com/sexintercourse/p/17029804.html

相关文章

  • SpringBoot过滤器/拦截器
    不同点项过滤器拦截器使用场景对请求/响应进行修改、判断等。一般用于过滤参数、登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换。在service或者一个方法前......
  • SpringCloud 2020.x.x工程bootstrap引导配置不生效的解决方案
      关注公众号风色年代(itfantasycc)500GJava微服务资料合集送上~注意:2020版本以后,添加spring-cloud-context是没有用的,因为官方重构了bootstrap引导配置的加载方式需要增......
  • React组件之间的通信方式总结(下)
    一、写一个时钟用react写一个每秒都可以更新一次的时钟importReactfrom'react'importReactDOMfrom'react-dom'functiontick(){letele=<h1>{ne......
  • React组件之间的通信方式总结(上)
    先来几个术语:官方我的说法对应代码ReactelementReact元素letelement=<span>A爆了</span>Component组件classAppextendsReact.Component{}无Ap......
  • 前端一面react面试题总结
    redux与mobx的区别?两者对⽐:redux将数据保存在单⼀的store中,mobx将数据保存在分散的多个store中redux使⽤plainobject保存数据,需要⼿动处理变化后的操作;mobx适⽤observ......
  • 美团前端一面必会react面试题
    state和props触发更新的生命周期分别有什么区别?state更新流程:这个过程当中涉及的函数:shouldComponentUpdate:当组件的state或props发生改变时,都会首先触发这......
  • springMVC常用注解介绍
    @Controller注解一个类表示控制器,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model......
  • springboot使用redis实现计数限流
    lua脚本resources下创建文件redis/AccessLimit.lua内容为:locallimitSecond=tonumber(ARGV[1])locallimitMaxCount=tonumber(ARGV[2])localnum=tonumber(......
  • 如何跳出springboot的service层中某一个方法?
    有一个需求,就是中断某个方法中的for循环目前的做法是:for循环中,增加if判断,如果满足条件就return,会中断这个方法for(inti=0;i<totalIndex;i++){............
  • Spring boot开发中的错误1——Invalid bound statement
    错误信息:"Invalidboundstatement(notfound):com.xxx.xxxService.list"这个错误浪费了我一天时间(ಥ_ಥ),希望这篇文章能帮大家找到一个可能的错误之处!我在网上查阅......