rc-tween-one
Version:
tween-one anim component for react
382 lines (331 loc) • 12.7 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
var _util = require('./util');
var _Tween = require('./Tween');
var _Tween2 = _interopRequireDefault(_Tween);
var _ticker = require('./ticker');
var _ticker2 = _interopRequireDefault(_ticker);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function noop() {}
var perFrame = Math.round(1000 / 60);
var objectOrArray = _propTypes2['default'].oneOfType([_propTypes2['default'].object, _propTypes2['default'].array]);
var TweenOne = function (_Component) {
(0, _inherits3['default'])(TweenOne, _Component);
function TweenOne(props) {
(0, _classCallCheck3['default'])(this, TweenOne);
var _this = (0, _possibleConstructorReturn3['default'])(this, (TweenOne.__proto__ || Object.getPrototypeOf(TweenOne)).call(this, props));
_initialiseProps.call(_this);
_this.rafID = -1;
_this.setDefalut(props);
_this.paused = props.paused;
_this.reverse = props.reverse;
_this.updateAnim = false;
_this.forced = {};
_this.setForcedJudg(props);
return _this;
}
(0, _createClass3['default'])(TweenOne, [{
key: 'componentDidMount',
value: function componentDidMount() {
this.dom = _reactDom2['default'].findDOMNode(this);
if (this.dom && this.dom.nodeName !== '#text') {
this.start();
}
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if (!this.tween && !this.dom) {
this.updateAnim = true;
return;
}
// 动画处理
var newAnimation = nextProps.animation;
var currentAnimation = this.props.animation;
var equal = (0, _util.objectEqual)(currentAnimation, newAnimation);
if (!equal) {
if (nextProps.resetStyle && this.tween) {
this.tween.resetDefaultStyle();
}
this.setDefalut(nextProps);
this.updateAnim = true;
}
// 跳帧事件 moment;
var nextMoment = nextProps.moment;
if (typeof nextMoment === 'number' && nextMoment !== this.props.moment) {
if (this.tween && !this.updateAnim) {
this.startMoment = nextMoment;
this.startFrame = _ticker2['default'].frame;
if (nextProps.paused) {
this.raf();
}
if (this.tween.progressTime >= this.tween.totalTime) {
this.play();
}
} else {
this.setDefalut(nextProps);
this.updateAnim = true;
}
}
// 暂停倒放
if (this.paused !== nextProps.paused || this.reverse !== nextProps.reverse) {
this.paused = nextProps.paused;
this.reverse = nextProps.reverse;
if (this.paused) {
this.cancelRequestAnimationFrame();
} else if (this.reverse && nextProps.reverseDelay) {
this.cancelRequestAnimationFrame();
_ticker2['default'].timeout(this.restart, nextProps.reverseDelay);
} else {
// 在 form 状态下,暂停时拉 moment 时,start 有值恢复播放,在 delay 的时间没有处理。。
if (this.tween) {
this.tween.resetAnimData();
this.tween.resetDefaultStyle();
}
if (!this.updateAnim) {
this.restart();
}
}
}
var styleEqual = (0, _util.objectEqual)(this.props.style, nextProps.style);
if (!styleEqual) {
// 在动画时更改了 style, 作为更改开始数值。
if (this.tween) {
this.tween.reStart(nextProps.style);
if (this.paused) {
this.raf();
}
}
}
this.setForcedJudg(nextProps);
}
}, {
key: 'componentDidUpdate',
value: function componentDidUpdate() {
if (!this.dom) {
this.dom = _reactDom2['default'].findDOMNode(this);
}
// 样式更新了后再执行动画;
if (this.updateAnim && this.dom && this.dom.nodeName !== '#text') {
if (this.tween) {
this.cancelRequestAnimationFrame();
}
this.start();
}
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
this.cancelRequestAnimationFrame();
}
/**
* @method setForcedJudg
* @param props
* QueueAnim 套在组件下面后导至子级变化。
* <QueueAnim component={Menu} >
* <SubMenu key="a" title="导航">
* <Item />
* </SubMenu>
* </QueueAnim>
* rc-Menu 里是以 isXXX 来判断是 rc-Menu 的子级;
* 如: 用 isSubMenu 来处理 hover 事件
* 地址: https://github.com/react-component/menu/blob/master/src/MenuMixin.js#L172
* 暂时方案: 在组件里添加判断用的值。
*/
}, {
key: 'render',
value: function render() {
var props = (0, _extends3['default'])({}, this.props);
['animation', 'component', 'componentProps', 'reverseDelay', 'attr', 'paused', 'reverse', 'repeat', 'yoyo', 'moment', 'resetStyle', 'forcedJudg'].forEach(function (key) {
return delete props[key];
});
props.style = (0, _extends3['default'])({}, this.props.style);
Object.keys(props.style).forEach(function (p) {
if (p.match(/filter/i)) {
['Webkit', 'Moz', 'Ms', 'ms'].forEach(function (prefix) {
props.style[prefix + 'Filter'] = props.style[p];
});
}
});
// component 为空时调用子级的。。
if (!this.props.component) {
if (!this.props.children) {
return this.props.children;
}
var childrenProps = this.props.children.props;
var style = childrenProps.style,
className = childrenProps.className;
// 合并 style 与 className。
var newStyle = (0, _extends3['default'])({}, style, props.style);
var newClassName = props.className ? props.className + ' ' + className : className;
return _react2['default'].cloneElement(this.props.children, { style: newStyle, className: newClassName });
}
return _react2['default'].createElement(this.props.component, (0, _extends3['default'])({}, props, this.props.componentProps));
}
}]);
return TweenOne;
}(_react.Component);
TweenOne.propTypes = {
component: _propTypes2['default'].any,
componentProps: _propTypes2['default'].any,
animation: objectOrArray,
children: _propTypes2['default'].any,
style: _propTypes2['default'].object,
paused: _propTypes2['default'].bool,
reverse: _propTypes2['default'].bool,
reverseDelay: _propTypes2['default'].number,
yoyo: _propTypes2['default'].bool,
repeat: _propTypes2['default'].number,
moment: _propTypes2['default'].number,
attr: _propTypes2['default'].string,
onChange: _propTypes2['default'].func,
resetStyle: _propTypes2['default'].bool,
forcedJudg: _propTypes2['default'].object
};
TweenOne.defaultProps = {
component: 'div',
componentProps: {},
reverseDelay: 0,
repeat: 0,
attr: 'style',
onChange: noop
};
var _initialiseProps = function _initialiseProps() {
var _this2 = this;
this.setForcedJudg = function (props) {
Object.keys(_this2.forced).forEach(function (key) {
delete _this2[key];
delete _this2.forced[key];
});
if (props.forcedJudg) {
Object.keys(props.forcedJudg).forEach(function (key) {
if (!_this2[key]) {
_this2[key] = props.forcedJudg[key];
_this2.forced[key] = 1;
}
});
}
};
this.setDefalut = function (props) {
_this2.moment = props.moment || 0;
_this2.startMoment = props.moment || 0;
_this2.startFrame = _ticker2['default'].frame;
};
this.restart = function () {
if (!_this2.tween) {
return;
}
_this2.startMoment = _this2.moment;
_this2.startFrame = _ticker2['default'].frame;
_this2.tween.reverse = _this2.reverse;
_this2.tween.reverseStartTime = _this2.startMoment;
_this2.raf();
_this2.play();
};
this.start = function () {
_this2.updateAnim = false;
var props = _this2.props;
if (props.animation && Object.keys(props.animation).length) {
_this2.tween = new _Tween2['default'](_this2.dom, (0, _util.dataToArray)(props.animation), { attr: props.attr });
_this2.tween.reverse = _this2.reverse;
// 预先注册 raf, 初始动画数值。
_this2.raf();
// 开始动画
_this2.play();
}
};
this.play = function () {
_this2.cancelRequestAnimationFrame();
if (_this2.paused) {
return;
}
_this2.rafID = _ticker2['default'].add(_this2.raf);
};
this.frame = function () {
var yoyo = _this2.props.yoyo;
var repeat = _this2.props.repeat;
var totalTime = repeat === -1 ? Number.MAX_VALUE : _this2.tween.totalTime * (repeat + 1);
repeat = repeat >= 0 ? repeat : Number.MAX_VALUE;
var moment = (_ticker2['default'].frame - _this2.startFrame) * perFrame + _this2.startMoment;
if (_this2.reverse) {
moment = (_this2.startMoment || 0) - (_ticker2['default'].frame - _this2.startFrame) * perFrame;
}
moment = moment > totalTime ? totalTime : moment;
moment = moment <= 0 ? 0 : moment;
var repeatNum = Math.floor(moment / _this2.tween.totalTime) || 0;
repeatNum = repeatNum > repeat ? repeat : repeatNum;
var tweenMoment = moment - _this2.tween.totalTime * repeatNum;
tweenMoment = tweenMoment < perFrame && !_this2.reverse ? 0 : tweenMoment;
if (repeat && moment && moment - _this2.tween.totalTime * repeatNum < perFrame) {
// 在重置样式之前补 complete;
_this2.tween.frame(_this2.tween.totalTime * repeatNum);
}
if (moment < _this2.moment && !_this2.reverse || repeat !== 0 && repeatNum && tweenMoment <= perFrame) {
// 在 form 状态下,暂停时拉 moment 时,start 有值,,往返方向播放时,在 delay 的时间没有处理。。
// 与上面的处理一样,删除 start ,重新走一遍 start。。
_this2.tween.resetAnimData();
_this2.tween.resetDefaultStyle();
}
var yoyoReverse = yoyo && repeatNum % 2;
if (yoyoReverse) {
tweenMoment = _this2.tween.totalTime - tweenMoment;
}
_this2.tween.onChange = function (e) {
var cb = (0, _extends3['default'])({}, e, {
timelineMode: ''
});
if (!moment && !_this2.reverse || _this2.reverse && _this2.moment === _this2.startMoment) {
cb.timelineMode = 'onTimelineStart';
} else if (moment >= totalTime && !_this2.reverse || !moment && _this2.reverse) {
cb.timelineMode = 'onTimelineComplete';
} else if (repeatNum !== _this2.timelineRepeatNum) {
cb.timelineMode = 'onTimelineRepeat';
} else {
cb.timelineMode = 'onTimelineUpdate';
}
_this2.props.onChange(cb);
};
_this2.moment = moment;
_this2.timelineRepeatNum = repeatNum;
_this2.tween.frame(tweenMoment);
};
this.raf = function () {
var tween = _this2.tween;
_this2.frame();
if (tween !== _this2.tween) {
// 在 onComplete 时更换动画时,raf 没结束,所以需要强制退出,避逸两个时间的冲突。
return null;
}
var repeat = _this2.props.repeat;
var totalTime = repeat === -1 ? Number.MAX_VALUE : _this2.tween.totalTime * (repeat + 1);
if (_this2.moment >= totalTime && !_this2.reverse || _this2.paused || _this2.reverse && _this2.moment === 0) {
return _this2.cancelRequestAnimationFrame();
}
return null;
};
this.cancelRequestAnimationFrame = function () {
_ticker2['default'].clear(_this2.rafID);
_this2.rafID = -1;
};
};
TweenOne.isTweenOne = true;
exports['default'] = TweenOne;
module.exports = exports['default'];