UNPKG

rc-tween-one

Version:
265 lines (244 loc) 9.57 kB
import _extends from 'babel-runtime/helpers/extends'; import _classCallCheck from 'babel-runtime/helpers/classCallCheck'; import _createClass from 'babel-runtime/helpers/createClass'; import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn'; import _inherits from 'babel-runtime/helpers/inherits'; import React, { Component, createElement } from 'react'; import PropTypes from 'prop-types'; import TweenOne from './TweenOne'; import { dataToArray, toArrayChildren, getChildrenFromProps, mergeChildren, transformArguments, findChildInChildrenByKey } from './util'; function noop() {} var TweenOneGroup = function (_Component) { _inherits(TweenOneGroup, _Component); function TweenOneGroup(props) { _classCallCheck(this, TweenOneGroup); var _this = _possibleConstructorReturn(this, (TweenOneGroup.__proto__ || Object.getPrototypeOf(TweenOneGroup)).call(this, props)); _initialiseProps.call(_this); _this.keysToEnter = []; _this.keysToLeave = []; _this.saveTweenTag = {}; _this.onEnterBool = false; _this.animQueue = []; _this.isTween = {}; // 第一进入,appear 为 true 时默认用 enter 或 tween-one 上的效果 var children = toArrayChildren(getChildrenFromProps(_this.props)); _this.originalChildren = toArrayChildren(getChildrenFromProps(_this.props)); _this.currentChildren = toArrayChildren(getChildrenFromProps(_this.props)); _this.state = { children: children }; return _this; } _createClass(TweenOneGroup, [{ key: 'componentDidMount', value: function componentDidMount() { this.onEnterBool = true; } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { var nextChildren = toArrayChildren(nextProps.children); if (Object.keys(this.isTween).length && !nextProps.exclusive) { this.animQueue.push(nextChildren); return; } var currentChildren = toArrayChildren(nextProps.exclusive ? this.originalChildren : this.state.children); this.changeChildren(nextChildren, currentChildren); } }, { key: 'componentDidUpdate', value: function componentDidUpdate() { this.originalChildren = toArrayChildren(getChildrenFromProps(this.props)); } }, { key: 'changeChildren', value: function changeChildren(nextChildren, currentChildren) { var _this2 = this; var newChildren = mergeChildren(currentChildren, nextChildren); this.keysToEnter = []; this.keysToLeave = []; nextChildren.forEach(function (c) { if (!c) { return; } var key = c.key; var hasPrev = findChildInChildrenByKey(currentChildren, key); // 如果当前 key 已存在 saveTweenTag 里,,刷新 child; if (_this2.saveTweenTag[key]) { _this2.saveTweenTag[key] = React.cloneElement(_this2.saveTweenTag[key], {}, c); } if (!hasPrev && key) { _this2.keysToEnter.push(key); } }); currentChildren.forEach(function (c) { if (!c) { return; } var key = c.key; var hasNext = findChildInChildrenByKey(nextChildren, key); if (!hasNext && key) { _this2.keysToLeave.push(key); delete _this2.saveTweenTag[key]; } }); this.currentChildren = newChildren; this.setState({ children: newChildren }); } }, { key: 'render', value: function render() { var childrenToRender = this.getChildrenToRender(this.state.children); if (!this.props.component) { return childrenToRender[0] || null; } var componentProps = _extends({}, this.props); ['component', 'componentProps', 'appear', 'enter', 'leave', 'animatingClassName', 'onEnd', 'exclusive'].forEach(function (key) { return delete componentProps[key]; }); return createElement(this.props.component, _extends({}, componentProps, this.props.componentProps), childrenToRender); } }]); return TweenOneGroup; }(Component); var _initialiseProps = function _initialiseProps() { var _this3 = this; this.onChange = function (animation, key, type, obj) { var length = dataToArray(animation).length; var tag = obj.target; var classIsSvg = typeof tag.className === 'object' && 'baseVal' in tag.className; var isEnter = type === 'enter' || type === 'appear'; if (obj.mode === 'onStart') { if (classIsSvg) { tag.className.baseVal = _this3.setClassName(tag.className.baseVal, isEnter); } else { tag.className = _this3.setClassName(tag.className, isEnter); } } else if (obj.index === length - 1 && obj.mode === 'onComplete') { delete _this3.isTween[key]; if (classIsSvg) { tag.className.baseVal = tag.className.baseVal.replace(_this3.props.animatingClassName[isEnter ? 0 : 1], '').trim(); } else { tag.className = tag.className.replace(_this3.props.animatingClassName[isEnter ? 0 : 1], '').trim(); } if (type === 'enter') { _this3.keysToEnter.splice(_this3.keysToEnter.indexOf(key), 1); if (!_this3.keysToEnter.length) { _this3.reAnimQueue(); } } else if (type === 'leave') { _this3.keysToLeave.splice(_this3.keysToLeave.indexOf(key), 1); _this3.currentChildren = _this3.currentChildren.filter(function (child) { return key !== child.key; }); if (!_this3.keysToLeave.length) { var currentChildrenKeys = _this3.currentChildren.map(function (item) { return item.key; }); Object.keys(_this3.saveTweenTag).forEach(function ($key) { if (currentChildrenKeys.indexOf($key) === -1) { delete _this3.saveTweenTag[$key]; } }); _this3.setState({ children: _this3.currentChildren }, _this3.reAnimQueue); } } var _obj = { key: key, type: type }; _this3.props.onEnd(_obj); } }; this.setClassName = function (name, isEnter) { var className = name.replace(_this3.props.animatingClassName[isEnter ? 1 : 0], '').trim(); if (className.indexOf(_this3.props.animatingClassName[isEnter ? 0 : 1]) === -1) { className = (className + ' ' + _this3.props.animatingClassName[isEnter ? 0 : 1]).trim(); } return className; }; this.getTweenChild = function (child) { var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var key = child.key; _this3.saveTweenTag[key] = React.createElement(TweenOne, _extends({}, props, { key: key, component: null }), child); return _this3.saveTweenTag[key]; }; this.getCoverAnimation = function (child, i, type) { var animation = void 0; animation = type === 'leave' ? _this3.props.leave : _this3.props.enter; if (type === 'appear') { var appear = transformArguments(_this3.props.appear, child.key, i); animation = appear && _this3.props.enter || null; } var animate = transformArguments(animation, child.key, i); var onChange = _this3.onChange.bind(_this3, animate, child.key, type); var props = { key: child.key, animation: animate, onChange: onChange, resetStyle: _this3.props.exclusive }; if (_this3.keysToEnter.concat(_this3.keysToLeave).indexOf(child.key) >= 0 || !_this3.onEnterBool && animation) { if (!_this3.saveTweenTag[child.key]) { _this3.isTween[child.key] = type; } } var children = _this3.getTweenChild(child, props); return children; }; this.getChildrenToRender = function (children) { return children.map(function (child, i) { if (!child || !child.key) { return child; } var key = child.key; if (_this3.keysToLeave.indexOf(key) >= 0) { return _this3.getCoverAnimation(child, i, 'leave'); } else if ((_this3.keysToEnter.indexOf(key) >= 0 || _this3.isTween[key] && _this3.keysToLeave.indexOf(key) === -1) && !(_this3.isTween[key] === 'enter' && _this3.saveTweenTag[key])) { /** * 1. 在 key 在 enter 里。 * 2. 出场未结束,触发进场, this.isTween[key] 为 leave, key 在 enter 里。 * 3. 状态为 enter 且 tweenTag 里有值时,不执行重载动画属性,直接调用 tweenTag 里的。 */ return _this3.getCoverAnimation(child, i, 'enter'); } else if (!_this3.onEnterBool) { return _this3.getCoverAnimation(child, i, 'appear'); } return _this3.saveTweenTag[key]; }); }; this.reAnimQueue = function () { if (!Object.keys(_this3.isTween).length && _this3.animQueue.length) { _this3.changeChildren(_this3.animQueue[_this3.animQueue.length - 1], _this3.state.children); _this3.animQueue = []; } }; }; TweenOneGroup.propTypes = { component: PropTypes.any, componentProps: PropTypes.object, children: PropTypes.any, style: PropTypes.object, appear: PropTypes.bool, enter: PropTypes.any, leave: PropTypes.any, animatingClassName: PropTypes.array, onEnd: PropTypes.func, exclusive: PropTypes.bool }; TweenOneGroup.defaultProps = { component: 'div', componentProps: {}, appear: true, animatingClassName: ['tween-one-entering', 'tween-one-leaving'], enter: { x: 50, opacity: 0, type: 'from' }, leave: { x: -50, opacity: 0 }, onEnd: noop, exclusive: false }; TweenOneGroup.isTweenOneGroup = true; export default TweenOneGroup;