• React之动画实现


    React之动画实现

    一,介绍与需求

    1.1,介绍

    1,Ant Motion

    Ant Motion能够快速在 React 框架中使用动画。在 React 框架下,只需要一段简单的代码就可以实现动画效果

    2,SVG 

    • SVG 指可伸缩矢量图形 (Scalable Vector Graphics)
    • SVG 用来定义用于网络的基于矢量的图形
    • SVG 使用 XML 格式定义图形
    • SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失
    • SVG 是万维网联盟的标准
    • SVG 与诸如 DOM 和 XSL 之类的 W3C 标准是一个整体

    1.2,需求

    提高网站的交互效果,提高用户体验。界面动效能加强用户认知且增加活力。

    二,基于Ant Motion的react动画

    2.1,动画效果

    1,snow掉落效果

    2,聚集与散开

     2.2,动画实现方式

    以掉落效果为例:

     1 import React from 'react';
     2 import Snow from './Snow';
     3 import './index.less';
     4 class App extends React.Component {
     5   constructor() {
     6     super(...arguments);
     7     this.state = {
     8       show: true,
     9     };
    10   }
    11   onEnd = () => {
    12     this.setState({
    13       show: false,
    14     });
    15   }
    16   render() {
    17     const children = Array(5).fill(1).map((c, i) => (
    18       <div key={i} className="addMoneyAnim" style={{ animationDelay: `${-Math.random() * 0.6}s` }} />
    19     ));
    20     return (
    21       <div className="snow-demo-wrapper" >
    22       <div className="snow-demo">
    23        
    24           <Snow onEnd={this.onEnd} >
    25             {children}
    26           </Snow>
    27         
    28       </div>
    29     </div>
    30     );
    31   }
    32 }
    33 
    34 export default App;

    组件snow代码:

      1   import React from 'react';
      2   import TweenOne from 'rc-tween-one';
      3   import BezierPlugin from 'rc-tween-one/lib/plugin/BezierPlugin';
      4   import PropTypes from 'prop-types';
      5   
      6   import './index.less';
      7   
      8   TweenOne.plugins.push(BezierPlugin);
      9   
     10   class Snow extends React.Component {
     11     static propTypes = {
     12       children: PropTypes.any,
     13       className: PropTypes.string,
     14       prefixCls: PropTypes.string,
     15       amount: PropTypes.number,
     16       repeat: PropTypes.number,
     17       ease: PropTypes.string,
     18       startArea: PropTypes.object,
     19       endArea: PropTypes.object,
     20       startDelayRandom: PropTypes.number,
     21       basicToDuration: PropTypes.number,
     22       randomToDuration: PropTypes.number,
     23       rotateRandom: PropTypes.number,
     24       bezierSegmentation: PropTypes.number,
     25       onEnd: PropTypes.func,
     26     }
     27     static defaultProps = {
     28       prefixCls: 'snow',
     29       amount: 10,
     30       repeat: 0,
     31       ease: 'linear',
     32       startArea: {
     33         x: 0, y: -200,  '100%', height: 50,
     34       },
     35       endArea: {
     36         x: -200, y: '100%',  '120%', height: 100,
     37       },
     38       basicToDuration: 1200,
     39       randomToDuration: 800,
     40       startDelayRandom: 800,
     41       rotateRandom: 180,
     42       bezierSegmentation: 2,
     43       onEnd: () => { },
     44     };
     45   
     46     constructor(props) {
     47       super(props);
     48       this.state = {
     49         children: null,
     50       };
     51     }
     52     componentDidMount() {
     53       this.setChilrenToState();
     54     }
     55   
     56     onAnimEnd = () => {
     57       this.animEnd += 1;
     58       if (this.animEnd >= this.props.amount) {
     59         this.animEnd = 0;
     60         if (this.props.onEnd) {
     61           this.props.onEnd();
     62         }
     63       }
     64     }
     65   
     66     setChilrenToState() {
     67       const children = this.getChildrenToRender();
     68       this.setState({
     69         children,
     70       });
     71     }
     72   
     73     getChildrenToRender = () => {
     74       const {
     75         bezierSegmentation, basicToDuration, randomToDuration,
     76         amount, ease, startDelayRandom, repeat, rotateRandom,
     77       } = this.props;
     78       const children = React.Children.toArray(this.props.children);
     79       const rect = this.wrapperDom.getBoundingClientRect();
     80       const startArea = this.dataToNumber(this.props.startArea, rect);
     81       const endArea = this.dataToNumber(this.props.endArea, rect);
     82       return Array(amount).fill(1).map((k, i) => {
     83         const item = children[Math.floor(Math.random() * children.length)];
     84         const vars = Array(bezierSegmentation).fill(1).map((c, j) => {
     85           const hegiht = endArea.y - startArea.y - startArea.height;
     86           const y = (hegiht / bezierSegmentation) * (j + 1);
     87           const x = Math.random() * (Math.max(startArea.width, endArea.width)
     88             + Math.min(startArea.x, endArea.x));
     89           // console.log(hegiht, startArea, endArea, y);
     90           return {
     91             y,
     92             x,
     93           };
     94         });
     95         const delay = Math.random() * startDelayRandom;
     96         const animation = {
     97           bezier: {
     98             type: 'soft',
     99             autRotate: true,
    100             vars,
    101           },
    102           ease,
    103           repeat,
    104           repeatDelay: delay,
    105           delay,
    106           duration: basicToDuration + Math.random() * randomToDuration,
    107           onComplete: this.onAnimEnd,
    108         };
    109         const style = {
    110           transform: `translate(${Math.random() * (startArea.width) + startArea.x}px, ${
    111             Math.random() * (startArea.height) + startArea.y
    112           }px)`,
    113         };
    114         const child = rotateRandom ? (
    115           <TweenOne
    116             className="snowRotate"
    117             style={{ transform: `rotate(${Math.random() * rotateRandom}deg)` }}
    118             animation={{
    119               rotate: 0,
    120               duration: animation.duration * 4 / 5,
    121               delay: animation.delay,
    122               repeat: animation.repeat,
    123             }}
    124           >
    125             {item}
    126           </TweenOne>
    127         ) : item;
    128         return (
    129           <TweenOne
    130             animation={animation}
    131             style={style}
    132             key={`${item}-${i.toString()}`}
    133             className="snowChild"
    134           >
    135             {child}
    136           </TweenOne>
    137         );
    138       });
    139     }
    140     dataToNumber = (obj, rect) => {
    141       const toNumber = (v, full) => {
    142         if (typeof v === 'number') {
    143           return v;
    144         }
    145         const unit = v.replace(/[0-9|.]/g, '');
    146         switch (unit) {
    147           case '%':
    148             return parseFloat(v) * full / 100;
    149           case 'em':
    150             return parseFloat(v) * 16;
    151           default:
    152             return null;
    153         }
    154       };
    155       return {
    156         x: toNumber(obj.x, rect.width),
    157         y: toNumber(obj.y, rect.height),
    158          toNumber(obj.width, rect.width),
    159         height: toNumber(obj.height, rect.height),
    160       };
    161     }
    162     animEnd = 0;
    163     render() {
    164       const { prefixCls, ...props } = this.props;
    165       const { children } = this.state;
    166       [
    167         'amount',
    168         'repeat',
    169         'ease',
    170         'startArea',
    171         'endArea',
    172         'basicToDuration',
    173         'randomToDuration',
    174         'startDelayRandom',
    175         'bezierSegmentation',
    176         'rotateRandom',
    177         'onEnd',
    178       ].forEach(k => delete props[k]);
    179       const className = `${prefixCls}${props.className ? ` ${props.className}` : ''}`;
    180       return (
    181         <div
    182           {...props}
    183           ref={(c) => {
    184             this.wrapperDom = c;
    185           }}
    186           className={className}
    187         >
    188           {children}
    189         </div>
    190       );
    191     }
    192   }
    193   export default Snow
    194   

    样式代码:

     1 .snow-demo-wrapper {
     2   background: #DFEAFF;
     3   overflow: hidden;
     4   height: 500px;
     5   display: flex;
     6   align-items: center;
     7   position: relative;
     8 }
     9 
    10 .snow-demo {
    11    300px;
    12   height: 90%;
    13   margin: auto;
    14   position: relative;
    15   background-image: url(https://gw.alipayobjects.com/zos/rmsportal/dNpuKMDHFEpMGrTxdLVR.jpg);
    16   background-position: top;
    17   background-size: 100% auto;
    18   box-shadow: 0 0 32px rgba(0, 0, 0, 0.15);
    19 }
    20 
    21 .snow {
    22    100%;
    23   height: 100%;
    24   position: absolute;
    25   top: 0;
    26   overflow: hidden;
    27 }
    28 
    29 .snowChild {
    30   position: absolute;
    31   top: 0;
    32   left: 0;
    33 }
    34 
    35 .snowRotate {
    36   transform-origin: center center;
    37 } 

     2.3,动画分类

    1,单元素动画rc-tween-one

    1 cnpm install rc-tween-one --save

    2,css样式动画rc-animate

    1 cnpm install rc-animate --save

    3,QueueAnim进出场动画

    1 cnpm install rc-queue-anim --save

    4,TextyAnim文字动画

    1 cnpm install rc-texty --save

    5,ScrollAnim页面滚动动画

    1 cnpm install rc-scroll-anim --save

    6,Banner动画

    1 cnpm install rc-banner-anim --save

    详细动画实例可查看官网

    三,基于svg的react动画

    3.1,动画效果

    鼠标移入动画执行,鼠标移出动画停止

    1,纵队动画

    2,俄罗斯方块

    3,坐标动画

    3.2,动画实现方式

    以纵队动画为例如下代码:

     1 import React from 'react';
     2 import Column from '../technology/Column';//实现动画的svg组件
     3 
     4 export default class ReactAnimation extends React.Component {
     5   constructor(props) {
     6     super(props);
     7     this.state = {
     8       hover: null,//是否有鼠标的移入
     9     };
    10   }
    11 
    12   onMouseEnter = (hover) => {//鼠标移入
    13     this.setState({
    14       hover,
    15     });
    16   };
    17   onMouseLeave = () => {//鼠标移出
    18     this.setState({
    19       hover: null,
    20     });
    21   };
    22   render() {
    23 
    24     return (
    25       <div>
    26          <div
    27             onMouseEnter={() => { this.onMouseEnter(1); }}
    28             onMouseLeave={this.onMouseLeave}
    29           >
    30          <div>
    31               {Column && React.createElement(Column, {
    32                 hover:this.state.hover === 1,
    33               })}
    34             </div>
    35             </div>
    36       </div>
    37     );
    38   }
    39 }

    React.createElement(): 根据指定的第一个参数创建一个React元素。

    1 React.createElement(
    2   type,
    3   [props],
    4   [...children]
    5 )

    第一个参数是必填,传入的是似HTML标签名称,如: ul, li 
    第二个参数是选填,表示的是属性,如: className 
    第三个参数是选填, 子节点,如: 要显示的文本内容

    SVG配置组件Column.jsx:

     1 import React from 'react';
     2 import TweenOne from 'rc-tween-one';//引入动画插件
     3 
     4 function TweenOneG(props) {
     5   function getAnimation() {
     6     return props.animation.map((item, i) => {
     7       return { ...item, duration: 400 };
     8     });
     9   }
    10   return (
    11     <TweenOne
    12       component="g"
    13       {...props}
    14       animation={
    15         props.animation ?
    16           getAnimation() :
    17           null
    18       }
    19     />);
    20 }
    21 
    22 export default class Column extends React.PureComponent {
    23   render() {
    24     const { hover } = this.props;
    25     return (
    26       <svg width="328px" height="150px" viewBox="0 0 328 150">
    27         <defs>
    28           <linearGradient x1="50%" y1="3.05125957%" x2="50%" y2="157.404891%" id="linearGradient-1">
    29             <stop stopColor="#2898FF" offset="0%" />
    30           </linearGradient>
    31         </defs>
    32         <g id="Page-1" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
    33           <TweenOneG animation={hover ? [{ y: -20 }, { y: -10 }, { y: -30 }] : this.default1Anim}>
    34             <g id="Group-33" transform="translate(0.000000, 116.000000)">
    35               <rect id="Rectangle-15" fill="#1890FF" opacity="0.03" x="0" y="2" width="20" height="145" />
    36             </g>
    37           </TweenOneG>
    38         </g>
    39       </svg>);
    40   }
    41 }

     上面展示的只是部分代码,如需完整的代码,请先留言评论加关注

  • 相关阅读:
    XML 加密、解密
    word 转 pdf
    PowerDesigner(PowerDesigner15.1.0.2850)下载、安装以及破解
    SQL 2005 18456
    SQL 2005端口的修改
    SQL——统计查询
    由于启动用户实例的进程时出错,导致无法生成 SQL Server 的用户实例 解决办法
    ASP.NET MVC中Model View Controller的开发顺序
    使用Windows身份验证的Intranet网站安全管理 Windows Authentication
    ASP.NET web.config中数据库连接字符串connectionStrings节的配置
  • 原文地址:https://www.cnblogs.com/jackson-yqj/p/10143766.html
Copyright © 2020-2023  润新知