• 在React中写一个Animation组件,为组件进入和离开加上动画/过度


    问题

    在单页面应用中,我们经常需要给路由的切换或者元素的挂载和卸载加上过渡效果,为这么一个小功能引入第三方框架,实在有点小纠结。不如自己封装。

    思路

    原理

    以进入时opacity: 0 --> opacity: 1 ,退出时opacity: 0 --> opacity: 1为例

    元素挂载时

    1. 挂载元素dom
    2. 设置动画opacity: 0 --> opacity: 1

    元素卸载时

    1. 设置动画opacity: 0 --> opacity: 1
    2. 动画结束后卸载dom

    组件设计

    为了使得组件简单易用、低耦合,我们期望如下方式来调用组件:

    属性名 类型 描述
    isShow Boolean 子元素显示或隐藏控制
    name String 指定一个name,动画进入退出时的动画

    App.jsx里调用组件:

    通过改变isShow的值来指定是否显示

    // App.jsx
    // 其他代码省略
    import './app.css';
    
    <Animation isShow={isShow} name='demo'>
        <div class='demo'>
            demo
        </div>
    </Animation>
    // 通过改变isShow的值来指定是否显示
    

    App.css里指定进入离开效果:

    // 基础样式
    .demo {
         200px;
        height: 200px;
        background-color: red;
    }
    
    // 定义进出入动画
    .demo-showing {
        animation: show 0.5s forwards;
    }
    .demo-fading {
        animation: fade 0.5s forwards;
    }
    
    // 定义动画fade与show
    @keyframes show {
        from {
            opacity: 0;
        }
        to {
            opacity: 1;
        }
    }
    
    @keyframes fade {
        from {
            opacity: 1;
        }
        to {
            opacity: 0;
        }
    }
    
    

    根据思路写代码

    // Animation.jsx
    import { PureComponent } from 'react';
    import './index.css';
    
    class Animation extends PureComponent {
        constructor(props) {
            super(props);
            this.state = {
                isInnerShow: false,
                animationClass: '',
            };
        }
    
        componentWillReceiveProps(props) {
            const { isShow } = props;
            if (isShow) {
                // 显示
                this.show().then(() => {
                    this.doShowAnimation();
                });
            } else {
                // 隐藏
                this.doFadeAnimation();
            }
        }
    
        handleAnimationEnd() {
            const isFading = this.state.animationClass === this.className('fading');
            if (isFading) {
                this.hide();
            }
        }
    
        show() {
            return new Promise(resolve => {
                this.setState(
                    {
                        isInnerShow: true,
                    },
                    () => {
                        resolve();
                    }
                );
            });
        }
    
        hide() {
            this.setState({
                isInnerShow: false,
            });
        }
    
        doShowAnimation() {
            this.setState({
                animationClass: this.className('showing'),
            });
        }
    
        doFadeAnimation() {
            this.setState({
                animationClass: this.className('fading'),
            });
        }
    
        /**
         * 获取className
         * @param {string} inner 'showing' | 'fading'
         */
        className(inner) {
            const { name } = this.props;
            if (!name) throw new Error('animation name must be assigned');
            return `${name}-${inner}`;
        }
    
        render() {
            let { children } = this.props;
            children = React.Children.only(children);
            const { isInnerShow, animationClass } = this.state;
            const element = {
                ...children,
                props: {
                    ...children.props,
                    className: `${children.props.className} ${animationClass}`,
                    onAnimationEnd: this.handleAnimationEnd.bind(this),
                },
            };
            return isInnerShow && element;
        }
    }
    
    export default Animation;
    
    

    Demo示例

    点我直达

  • 相关阅读:
    winform中Dock的布局规则
    如何为VS添加编写NHibernate配置文件智能提示的功能
    c# winform 给PictureBox控件添上滚动条,使用滚动条来查看图片,panel滚动条
    Nhibernate使用中遇到的问题
    Best gotchas of C++/CLI
    关于progressbar
    对象序列化
    10个非常不错的CSS技巧
    清除浮动
    Sublime Text2 常用快捷键
  • 原文地址:https://www.cnblogs.com/looyulong/p/11071478.html
Copyright © 2020-2023  润新知