1

我的目标是有一个保存指示器,当数据刚刚保存时(不是在保存时)闪烁保存图标,作为向用户指示他们的编辑成功的指示。React 似乎比一次性的“动作”更适合状态,但这是我能想到的最好的:

import React, { PureComponent, PropTypes } from 'react';
import Radium from 'radium';
import moment from 'moment';
import { ContentSave as SaveIcon } from 'material-ui/svg-icons';

class SaveIndicator extends PureComponent {
  getStyles = () => {
    if (!this.props.saving) return { opacity: 0 };

    return {
      animation: 'x 700ms ease 0s 3 normal forwards',
      animationName: saveAnimation,
    };
  };

  render() {
    return <div style={styles.root}>
      <div style={{ display: 'flex' }}>
        <div style={{ marginRight: 16 }}>
          Last saved {moment(this.props.lastSaved).fromNow()}
        </div>
        <div
          style={this.getStyles()}
          onAnimationEnd={() => this.props.onIndicationComplete()}
        >
          <SaveIcon color="#666" />
        </div>
      </div>
    </div>
  }
}

const saveAnimation = Radium.keyframes({
  '0%': { opacity: 0 },
  '50%': { opacity: 1 },
  '100%': { opacity: 0 },
});

const styles = {
  root: {
    display: 'inline-block',
  },
};

SaveIndicator.defaultProps = {
  saving: false,
};

SaveIndicator.propTypes = {
  lastSaved: PropTypes.object.isRequired,
  onIndicationComplete: PropTypes.func,
  saving: PropTypes.bool,
};

export default Radium(SaveIndicator)

它有效,但是有没有办法可以简化它并使其更短?

4

1 回答 1

0

这个怎么样。不久前我有一个组件需要类似于您所描述的内容。我将它粘贴进去,因为它可以完全工作,但策略有点像这样:传递一个时间来启动动画。该道具触发一个函数来启动动画,该动画捕捉那个时间和“现在”之间的差异。它迭代地设置状态以缩小初始时间和现在之间的差距,直到它超过传入的持续时间道具。

class SaveIndicator extends Component {
    static propTypes = {
        children: Types.element,
        // time in milliseconds when the save is started; can change
        indicationStartTime: Types.number.isRequired,
        // time in milliseconds that the animation will take to fade
        duration: Types.number,
        // time in milliseconds to wait between renderings
        frameRate: Types.number,
    };

    static defaultProps = {
        duration: 7000,
        frameRate: 100,
    }

    constructor(props) {
        super(props);
        this.state = { opacity: 0 };
    }

    componentDidMount() {
        this.startAnimation();
    }

    componentWillReceiveProps({ indicationStartTime }) {
        if (indicationStartTime !== this.props.indicationStartTime) {
            this.startAnimation();
        }
    }

    startAnimation() {
        const { indicationStartTime, duration, frameRate } = this.props;
        const now = new Date().getTime();
        const newOpacity = 1 - ((now - indicationStartTime) / duration);

        if (now - indicationStartTime < duration) {
            this.setState({ opacity: newOpacity }, () =>
                setTimeout(::this.startAnimation, frameRate)
            );
        } else {
            this.setState({ opacity: 0 });
        }
    }

    render() {
        const { children } = this.props;
        const { opacity } = this.state;
        const style = { opacity };

        return <div style={style}>{children}</div>;
    }
}
于 2016-11-05T05:06:57.353 回答