yunjiwong-slider
Version:
banner-anim animation component for react
311 lines (288 loc) • 10.3 kB
JavaScript
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 } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import Arrow from './Arrow';
import Thumb from './Thumb';
import ticker from 'rc-tween-one/es/ticker';
import { toArrayChildren, dataToArray } from './utils';
import animType from './anim';
var BannerAnim = function (_Component) {
_inherits(BannerAnim, _Component);
function BannerAnim() {
_classCallCheck(this, BannerAnim);
var _this = _possibleConstructorReturn(this, (BannerAnim.__proto__ || Object.getPrototypeOf(BannerAnim)).apply(this, arguments));
_this.onMouseEnter = function () {
_this.props.onMouseEnter();
if (_this.props.autoPlay) {
ticker.clear(_this.autoPlayId);
}
};
_this.onMouseLeave = function () {
_this.props.onMouseLeave();
if (_this.props.autoPlay) {
_this.autoPlay();
}
};
_this.onTouchStart = function (e) {
_this.mouseXY = {
startX: e.touches === undefined ? e.clientX : e.touches[0].clientX,
startY: e.touches === undefined ? e.clientY : e.touches[0].clientY
};
};
_this.onTouchMove = function (e) {
if (!_this.mouseXY) {
return;
}
_this.mouseXY.currentX = e.touches === undefined ? e.clientX : e.touches[0].clientX;
_this.mouseXY.currentY = e.touches === undefined ? e.clientY : e.touches[0].clientY;
};
_this.onTouchEnd = function () {
if (!_this.mouseXY) {
return;
}
var differX = _this.mouseXY.currentX - _this.mouseXY.startX;
var differY = _this.mouseXY.currentY - _this.mouseXY.startY;
var r = Math.atan2(differY, differX);
var angle = Math.round(r * 180 / Math.PI);
angle = angle < 0 ? 360 - Math.abs(angle) : angle;
if ((angle >= 0 && angle <= 45 || angle >= 315) && differX > _this.state.domRect.width * 0.1) {
_this.prev();
} else if (angle >= 135 && angle <= 225 && differX < -_this.state.domRect.width * 0.1) {
_this.next();
}
delete _this.mouseXY;
};
_this.getRenderChildren = function (children) {
var elem = [];
var arrow = [];
var thumb = void 0;
var _animType = _this.getAnimType(_this.props.type);
toArrayChildren(children).forEach(function (item, i) {
if (!item.key) {
throw new Error('Please add key, key is required');
}
var itemProps = _extends({}, item.props);
if (item.type.isBannerAnimElement) {
itemProps.key = item.key;
itemProps.callBack = _this.animEnd;
itemProps.show = _this.state.currentShow === i;
itemProps.animType = _animType;
itemProps.duration = _this.props.duration;
itemProps.delay = _this.props.delay;
itemProps.ease = _this.props.ease;
itemProps.sync = _this.props.sync || itemProps.sync;
itemProps.elemOffset = {
top: _this.state.domRect.top,
width: _this.state.domRect.width,
height: _this.state.wrapperHeight
};
itemProps.direction = _this.state.direction;
elem.push(React.cloneElement(item, itemProps));
} else if (item.type.isBannerAnimArrow) {
itemProps.next = _this.next;
itemProps.prev = _this.prev;
itemProps.elemHeight = _this.state.wrapperHeight;
arrow.push(React.cloneElement(item, itemProps));
} else if (item.type.isBannerAnimThumb) {
itemProps.thumbClick = _this.slickGoTo;
itemProps.active = _this.state.currentShow;
thumb = React.cloneElement(item, itemProps);
}
});
if (elem.length > 1) {
if (!arrow.length && _this.props.arrow) {
arrow.push(React.createElement(Arrow, { arrowType: 'prev', key: 'arrowPrev', next: _this.next, prev: _this.prev, 'default': true,
elemHeight: _this.state.wrapperHeight
}), React.createElement(Arrow, { arrowType: 'next', key: 'arrowNext', next: _this.next, prev: _this.prev, 'default': true,
elemHeight: _this.state.wrapperHeight
}));
}
if (!thumb && _this.props.thumb) {
thumb = React.createElement(Thumb, { length: elem.length, key: 'thumb',
thumbClick: _this.slickGoTo,
active: _this.state.currentShow,
'default': true
});
}
}
_this.elemWrapper = elem;
return elem.concat(arrow, thumb);
};
_this.getDomDataSetToState = function () {
_this.dom = ReactDOM.findDOMNode(_this);
var domRect = _this.dom.getBoundingClientRect();
var wrapperHeight = _this.getElementHeight(_this.dom.getElementsByClassName('banner-anim-elem'));
_this.setState({
wrapperHeight: wrapperHeight,
domRect: domRect
});
_this.tweenBool = false;
};
_this.getElementHeight = function (children) {
var height = 0;
for (var i = 0; i < children.length; i++) {
var dom = children[i];
var _height = dom.getBoundingClientRect().height;
height = height > _height ? height : _height;
}
return height;
};
_this.getAnimType = function (type) {
var typeArray = type ? dataToArray(type) : Object.keys(animType);
var random = Math.round(Math.random() * (typeArray.length - 1));
return animType[typeArray[random]];
};
_this.autoPlay = function () {
_this.autoPlayId = ticker.interval(_this.next, _this.props.autoPlaySpeed);
};
_this.animTweenStart = function (show, type) {
_this.props.onChange('before', show);
_this.setState({
currentShow: show,
direction: type
});
};
_this.animEnd = function (type) {
if (type === 'enter') {
_this.tweenBool = false;
_this.props.onChange('after', _this.state.currentShow);
}
};
_this.next = function () {
if (!_this.tweenBool) {
_this.tweenBool = true;
var newShow = _this.state.currentShow;
newShow++;
if (newShow >= _this.elemWrapper.length) {
newShow = 0;
}
_this.animTweenStart(newShow, 'next');
}
};
_this.prev = function () {
if (!_this.tweenBool) {
_this.tweenBool = true;
var newShow = _this.state.currentShow;
newShow--;
if (newShow < 0) {
newShow = _this.elemWrapper.length - 1;
}
_this.animTweenStart(newShow, 'prev');
}
};
_this.slickGoTo = function (i) {
if (!_this.tweenBool && i !== _this.state.currentShow) {
_this.tweenBool = true;
var type = i > _this.state.currentShow ? 'next' : 'prev';
_this.animTweenStart(i, type);
}
};
_this.state = {
currentShow: _this.props.initShow,
direction: null,
wrapperHeight: 0,
domRect: {}
};
_this.tweenBool = false;
return _this;
}
_createClass(BannerAnim, [{
key: 'componentDidMount',
value: function componentDidMount() {
this.getDomDataSetToState();
if (window.addEventListener) {
window.addEventListener('resize', this.getDomDataSetToState);
} else {
window.attachEvent('onresize', this.getDomDataSetToState);
}
if (this.props.autoPlay) {
this.autoPlay();
}
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps() {
this.tweenBool = false;
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
if (this.autoPlayId) {
ticker.clear(this.autoPlayId);
this.autoPlayId = 0;
}
if (window.addEventListener) {
window.removeEventListener('resize', this.getDomDataSetToState);
} else {
window.detachEvent('onresize', this.getDomDataSetToState);
}
}
}, {
key: 'render',
value: function render() {
var prefixCls = this.props.prefixCls;
var props = _extends({}, this.props);
['type', 'prefixCls', 'component', 'initShow', 'duration', 'delay', 'ease', 'arrow', 'thumb', 'autoPlaySpeed', 'autoPlay', 'thumbFloat', 'sync', 'dragPlay'].forEach(function (key) {
return delete props[key];
});
var childrenToRender = this.getRenderChildren(props.children);
props.className = (props.className + ' ' + (prefixCls || '')).trim();
props.style = _extends({}, props.style);
if (childrenToRender.length > 1 && this.props.dragPlay) {
props.onMouseEnter = this.onMouseEnter;
props.onMouseLeave = this.onMouseLeave;
props.onTouchStart = this.onTouchStart;
props.onMouseDown = this.onTouchStart;
props.onTouchMove = this.onTouchMove;
props.onMouseMove = this.onTouchMove;
props.onTouchEnd = this.onTouchEnd;
props.onMouseUp = this.onTouchEnd;
}
return React.createElement(this.props.component, props, childrenToRender);
}
}]);
return BannerAnim;
}(Component);
BannerAnim.propTypes = {
children: PropTypes.any,
style: PropTypes.object,
className: PropTypes.string,
prefixCls: PropTypes.string,
component: PropTypes.any,
arrow: PropTypes.bool,
thumb: PropTypes.bool,
initShow: PropTypes.number,
type: PropTypes.any,
duration: PropTypes.number,
delay: PropTypes.number,
ease: PropTypes.string,
autoPlay: PropTypes.bool,
autoPlaySpeed: PropTypes.number,
onChange: PropTypes.func,
onMouseEnter: PropTypes.func,
onMouseLeave: PropTypes.func,
sync: PropTypes.bool,
dragPlay: PropTypes.bool
};
BannerAnim.defaultProps = {
component: 'div',
className: 'banner-anim',
initShow: 0,
duration: 450,
delay: 0,
ease: 'easeInOutQuad',
arrow: true,
thumb: true,
autoPlaySpeed: 5000,
dragPlay: true,
onChange: function onChange() {},
onMouseEnter: function onMouseEnter() {},
onMouseLeave: function onMouseLeave() {}
};
BannerAnim.isBannerAnim = true;
export default BannerAnim;