zarm-mobile
Version:
UI for react.js
471 lines (387 loc) • 14.2 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _classnames2 = require('classnames');
var _classnames3 = _interopRequireDefault(_classnames2);
var _events = require('../utils/events');
var _events2 = _interopRequireDefault(_events);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var Swipe = function (_Component) {
_inherits(Swipe, _Component);
function Swipe(props) {
_classCallCheck(this, Swipe);
var _this = _possibleConstructorReturn(this, (Swipe.__proto__ || Object.getPrototypeOf(Swipe)).call(this, props));
_this.moveInterval = null;
_this.pointStart = 0;
_this.pointEnd = 0;
_this.timeStart = new Date();
_this.translateX = 0;
_this.state = {
items: [],
activeIndex: props.activeIndex
};
_this._updateResize = _this._updateResize.bind(_this);
_this._transitionEnd = _this._transitionEnd.bind(_this);
return _this;
}
_createClass(Swipe, [{
key: 'componentWillMount',
value: function componentWillMount() {
this._parseItem(this.props);
this.startAutoPlay(this.props);
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
// 监听窗口变化
_events2.default.on(window, 'resize', this._updateResize);
_events2.default.on(this.swipeItems, 'webkitTransitionEnd', this._transitionEnd);
_events2.default.on(this.swipeItems, 'transitionend', this._transitionEnd);
// 设置起始位置编号
this.onJumpTo(this.props.activeIndex);
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if ('children' in nextProps) {
this._parseItem(nextProps);
}
if ('activeIndex' in nextProps) {
this.onJumpTo(nextProps.activeIndex);
}
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
// 自动轮播结束
this.pauseAutoPlay();
// 移除监听窗口变化
_events2.default.off(window, 'resize', this._updateResize);
_events2.default.off(this.swipeItems, 'webkitTransitionEnd', this._transitionEnd);
_events2.default.off(this.swipeItems, 'transitionend', this._transitionEnd);
}
// 滑动到指定编号
}, {
key: 'onSlideTo',
value: function onSlideTo(index) {
this._onMoveTo(index, this.props.speed);
}
// 静默跳到指定编号
}, {
key: 'onJumpTo',
value: function onJumpTo(index) {
this._onMoveTo(index, 0);
}
// 自动轮播开始
}, {
key: 'startAutoPlay',
value: function startAutoPlay() {
var _this2 = this;
this.moveInterval = this.props.autoPlay && setInterval(function () {
var activeIndex = _this2.state.activeIndex;
var maxLength = _this2.props.children.length;
activeIndex = ['left', 'top'].indexOf(_this2.props.direction) > -1 ? activeIndex + 1 : activeIndex - 1;
if (activeIndex > maxLength - 1) {
// 不循环暂停轮播
if (!_this2.props.loop) {
_this2.pauseAutoPlay();
return;
}
activeIndex = 0;
_this2.onJumpTo(-1);
} else if (activeIndex < 0) {
activeIndex = maxLength - 1;
_this2.onJumpTo(maxLength);
}
_this2.onSlideTo(activeIndex);
}, this.props.autoPlayIntervalTime);
}
// 暂停自动轮播
}, {
key: 'pauseAutoPlay',
value: function pauseAutoPlay() {
if (this.moveInterval) {
clearInterval(this.moveInterval);
}
}
// 处理节点(首位拼接)
}, {
key: '_parseItem',
value: function _parseItem(props) {
if (props.children.length === 0) {
return;
}
// 增加头尾拼接节点
var items = [].concat(props.children);
var firstItem = items[0];
var lastItem = items[items.length - 1];
if (props.loop) {
items.push(firstItem);
items.unshift(lastItem);
}
// 节点追加后重排key
var newItems = _react2.default.Children.map(items, function (element, index) {
return (0, _react.cloneElement)(element, {
key: index
});
});
this.setState({
items: newItems
});
}
// 更新窗口变化的位置偏移
}, {
key: '_updateResize',
value: function _updateResize() {
this.onJumpTo(this.state.activeIndex);
}
// 移动到指定编号
}, {
key: '_onMoveTo',
value: function _onMoveTo(index, speed) {
var dom = this.swipeItems;
if (!dom) {
return;
}
var px = this._isDirectionX() ? -dom.offsetWidth * (index + this.props.loop) : -dom.offsetHeight * (index + this.props.loop);
this._doTransition(px, speed);
this.translateX = px;
this.setState({
activeIndex: index
});
}
// 执行过渡动画
}, {
key: '_doTransition',
value: function _doTransition(offset, duration) {
var dom = this.swipeItems;
var x = 0;
var y = 0;
if (this._isDirectionX()) {
x = offset;
} else {
y = offset;
}
dom.style.webkitTransitionDuration = duration + 'ms';
dom.style.transitionDuration = duration + 'ms';
dom.style.webkitTransform = 'translate3d(' + x + 'px, ' + y + 'px, 0)';
dom.style.transform = 'translate3d(' + x + 'px, ' + y + 'px, 0)';
}
}, {
key: '_transitionEnd',
value: function _transitionEnd() {
var activeIndex = this.state.activeIndex;
var maxLength = this.props.children.length;
if (activeIndex > maxLength - 1) {
this.onJumpTo(0);
} else if (activeIndex < 0) {
this.onJumpTo(maxLength - 1);
}
this.props.onChangeEnd(this.state.activeIndex);
}
// 触屏事件
}, {
key: '_onTouchStart',
value: function _onTouchStart(event) {
this.pauseAutoPlay();
var pointX = this._getCurrentPoint(event);
var activeIndex = this.state.activeIndex;
var maxLength = this.props.children.length;
// 跳转到头尾
if (activeIndex <= 0) {
this.onJumpTo(0);
} else if (activeIndex >= maxLength - 1) {
this.onJumpTo(maxLength - 1);
}
this.pointStart = pointX;
this.timeStart = new Date();
}
}, {
key: '_onTouchMove',
value: function _onTouchMove(event) {
event.preventDefault();
var pointX = this._getCurrentPoint(event);
var px = this.translateX + (pointX - this.pointStart);
// 设置不循环的时候
if (!this.props.loop) {
// 在首页时禁止拖动
if (this._isLastIndex() && pointX - this.pointStart < 0) {
return;
}
// 在尾页时禁止拖动
if (this._isFirstIndex() && pointX - this.pointStart > 0) {
return;
}
}
this._doTransition(px, 0);
this.pointEnd = pointX;
}
}, {
key: '_onTouchEnd',
value: function _onTouchEnd() {
var dom = this.swipeItems;
var px = this.pointEnd !== 0 ? this.pointEnd - this.pointStart : 0;
var timeSpan = new Date().getTime() - this.timeStart.getTime();
var activeIndex = this.state.activeIndex;
// 判断滑动临界点
// 1.滑动距离超过0,且滑动距离和父容器长度之比超过moveDistanceRatio
// 2.滑动释放时间差低于moveTimeSpan
if (
// 滑动距离超过0
px !== 0 && (
// 滑动距离和父容器长度之比超过moveDistanceRatio
Math.abs(px / dom.offsetWidth) >= this.props.moveDistanceRatio ||
// 滑动释放时间差低于moveTimeSpan
timeSpan <= this.props.moveTimeSpan)) {
activeIndex = px > 0 ? this.state.activeIndex - 1 : this.state.activeIndex + 1;
var onChange = this.props.onChange;
typeof onChange === 'function' && onChange(activeIndex);
}
this.onSlideTo(activeIndex);
this.pointStart = 0;
this.pointEnd = 0;
// 恢复自动轮播
this.startAutoPlay();
}
// 获取鼠标/触摸点坐标
}, {
key: '_getCurrentPoint',
value: function _getCurrentPoint(event, type) {
var touch = type === 'mouse' ? event : event.touches[0];
var offset = this._isDirectionX() ? touch.pageX : touch.pageY;
return offset;
}
// 判断当前是否在最后一页
}, {
key: '_isLastIndex',
value: function _isLastIndex() {
var result = false;
if (this.state.activeIndex >= this.props.children.length - 1) {
result = true;
}
return result;
}
// 判断当前是否在第一页
}, {
key: '_isFirstIndex',
value: function _isFirstIndex() {
var result = false;
if (this.state.activeIndex <= 0) {
result = true;
}
return result;
}
// 是否横向移动
}, {
key: '_isDirectionX',
value: function _isDirectionX() {
return ['left', 'right'].indexOf(this.props.direction) > -1;
}
}, {
key: 'render',
value: function render() {
var _classnames,
_this3 = this;
var _props = this.props,
prefixCls = _props.prefixCls,
className = _props.className,
height = _props.height,
children = _props.children;
var classes = (0, _classnames3.default)((_classnames = {}, _defineProperty(_classnames, '' + prefixCls, true), _defineProperty(_classnames, className, !!className), _classnames));
var style = {
items: {},
pagination: {}
};
if (!this._isDirectionX()) {
style.items.height = height;
style.pagination.marginTop = 3;
} else {
style.items.whiteSpace = 'nowrap';
style.pagination.display = 'inline-block';
style.pagination.marginRight = 3;
}
return _react2.default.createElement(
'div',
{ className: classes },
_react2.default.createElement(
'div',
{
ref: function ref(ele) {
_this3.swipeItems = ele;
},
className: prefixCls + '-items',
style: style.items,
onTouchStart: function onTouchStart(event) {
return _this3._onTouchStart(event);
},
onTouchMove: function onTouchMove(event) {
return _this3._onTouchMove(event);
},
onTouchEnd: function onTouchEnd(event) {
return _this3._onTouchEnd(event);
} },
this.state.items
),
_react2.default.createElement(
'div',
{ className: prefixCls + '-pagination' },
_react2.default.createElement(
'ul',
null,
_react.Children.map(children, function (result, index) {
return _react2.default.createElement('li', {
role: 'tab',
key: 'pagination-' + index,
className: (0, _classnames3.default)({ active: index === _this3.state.activeIndex }),
style: style.pagination,
onClick: function onClick() {
return _this3.onSlideTo(index);
}
});
})
)
)
);
}
}]);
return Swipe;
}(_react.Component);
Swipe.propTypes = {
prefixCls: _propTypes2.default.string,
direction: _propTypes2.default.oneOf(['left', 'right', 'top', 'bottom']),
height: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]),
loop: _propTypes2.default.bool,
activeIndex: _propTypes2.default.number,
speed: _propTypes2.default.number,
autoPlay: _propTypes2.default.bool,
autoPlayIntervalTime: _propTypes2.default.number,
moveDistanceRatio: _propTypes2.default.number,
moveTimeSpan: _propTypes2.default.number,
onChange: _propTypes2.default.func,
onChangeEnd: _propTypes2.default.func
};
Swipe.defaultProps = {
prefixCls: 'za-swipe',
direction: 'left',
height: 160,
loop: false,
activeIndex: 0,
speed: 300,
autoPlay: false,
autoPlayIntervalTime: 3000,
moveDistanceRatio: 0.5,
moveTimeSpan: 300,
onChange: function onChange() {},
onChangeEnd: function onChangeEnd() {}
};
exports.default = Swipe;