rc-banner-anim
Version:
banner-anim animation component for react
391 lines (364 loc) • 13 kB
JavaScript
import _extends from 'babel-runtime/helpers/extends';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
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 ticker from 'rc-tween-one/es/ticker';
import Arrow from './Arrow';
import Thumb from './Thumb';
import { toArrayChildren, dataToArray } from './utils';
import animType from './anim';
var BannerAnim = function (_Component) {
_inherits(BannerAnim, _Component);
function BannerAnim(props) {
_classCallCheck(this, BannerAnim);
var _this = _possibleConstructorReturn(this, _Component.call(this, props));
_this.onMouseEnter = function () {
_this.props.onMouseEnter();
if (_this.props.autoPlay) {
ticker.clear(_this.autoPlayId);
_this.autoPlayId = -1;
}
};
_this.onMouseLeave = function () {
_this.props.onMouseLeave();
if (_this.props.autoPlay) {
_this.autoPlay();
}
};
_this.onTouchStart = function (e) {
if (e.touches && e.touches.length > 1 || _this.elemWrapper.length <= 1 || _this.getDomIsArrowOrThumb(e) || e.button === 2) {
return;
}
if (_this.props.autoPlay) {
ticker.clear(_this.autoPlayId);
_this.autoPlayId = -1;
}
_this.animType = _this.getAnimType(_this.props.type);
_this.currentShow = _this.state.currentShow;
// this.mouseMoveType = 'start';
_this.mouseStartXY = {
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.mouseStartXY || e.touches && e.touches.length > 1) {
return;
}
var currentX = e.touches === undefined ? e.clientX : e.touches[0].clientX;
var differX = currentX - _this.mouseStartXY.startX;
if (!differX) {
return;
}
var ratio = differX / _this.state.domRect.width * 2;
var ratioType = _this.ratioType;
var currentShow = _this.currentShow;
if (ratio > 0) {
ratioType = '+';
} else {
ratioType = '-';
}
_this.mouseMoveType = 'update';
if (_this.ratioType !== ratioType) {
_this.ratioType = ratioType;
_this.mouseMoveType = 'reChild';
_this.setState({
currentShow: currentShow
});
return;
}
_this.ratio = ratio;
if (_this.ratio) {
var type = void 0;
if (_this.ratio > 0) {
currentShow += 1;
type = 'next';
} else {
currentShow -= 1;
type = 'prev';
}
_this.ratio = Math.abs(_this.ratio);
_this.ratio = _this.ratio > 1 ? 1 : _this.ratio;
currentShow = currentShow >= _this.elemWrapper.length ? 0 : currentShow;
currentShow = currentShow < 0 ? _this.elemWrapper.length - 1 : currentShow;
_this.setState({
currentShow: currentShow,
direction: type
});
}
};
_this.onTouchEnd = function (e) {
if (!_this.mouseStartXY || e.changedTouches && e.changedTouches.length > 1) {
return;
}
if (_this.props.autoPlay && _this.autoPlayId === -1) {
_this.autoPlay();
}
var currentX = e.changedTouches === undefined ? e.clientX : e.changedTouches[0].clientX;
var differX = currentX - _this.mouseStartXY.startX;
delete _this.mouseStartXY;
_this.mouseMoveType = 'end';
if (!differX) {
_this.mouseMoveType = '';
return;
}
if (_this.ratio > 0.3) {
_this.forceUpdate(function () {
_this.ratio = 0;
_this.mouseMoveType = '';
});
} else {
_this.setState({
currentShow: _this.currentShow,
direction: _this.ratioType === '+' ? 'prev' : 'next'
}, function () {
_this.ratio = 0;
_this.mouseMoveType = '';
});
}
};
_this.getDomIsArrowOrThumb = function (e) {
var arrowClassName = e.target.className;
var thumbClassName = e.target.parentNode.className;
if (arrowClassName.indexOf('banner-anim-arrow') >= 0 || thumbClassName.indexOf('banner-anim-thumb') >= 0) {
return true;
}
return false;
};
_this.getRenderChildren = function (children) {
var elem = [];
var arrow = [];
var thumb = void 0;
toArrayChildren(children).forEach(function (item, i) {
if (!item) {
return;
}
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 = _this.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;
itemProps.ratio = _this.ratio;
itemProps.mouseMoveType = _this.mouseMoveType;
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();
// 获取宽度与定位,setState刷新;
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.animType = _this.getAnimType(_this.props.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;
}
BannerAnim.prototype.componentDidMount = function componentDidMount() {
this.getDomDataSetToState();
if (window.addEventListener) {
window.addEventListener('touchend', this.onTouchEnd);
window.addEventListener('mouseup', this.onTouchEnd);
window.addEventListener('resize', this.getDomDataSetToState);
} else {
window.attachEvent('ontouchend', this.onTouchEnd);
window.attachEvent('onmouseup', this.onTouchEnd);
window.attachEvent('onresize', this.getDomDataSetToState);
}
if (this.props.autoPlay) {
this.autoPlay();
}
};
BannerAnim.prototype.componentWillReceiveProps = function componentWillReceiveProps() {
this.tweenBool = false;
};
BannerAnim.prototype.componentWillUnmount = function componentWillUnmount() {
if (this.autoPlayId) {
ticker.clear(this.autoPlayId);
this.autoPlayId = 0;
}
if (window.addEventListener) {
window.removeEventListener('touchend', this.onTouchEnd);
window.removeEventListener('mouseup', this.onTouchEnd);
window.removeEventListener('resize', this.getDomDataSetToState);
} else {
window.detachEvent('ontouchend', this.onTouchEnd);
window.attachEvent('onmouseup', this.onTouchEnd);
window.detachEvent('onresize', this.getDomDataSetToState);
}
};
BannerAnim.prototype.render = 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);
props.onMouseEnter = this.onMouseEnter;
props.onMouseLeave = this.onMouseLeave;
if (childrenToRender.length > 1 && this.props.dragPlay) {
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;