antd-mobile
Version:
基于 React 的移动设计规范实现
323 lines (308 loc) • 12.6 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';
/* tslint:disable:jsx-no-multiline-js */
import React from 'react';
import { View, Text, ScrollView, Platform } from 'react-native';
import CarouselStyle from './style';
var defaultPagination = function defaultPagination(props) {
var styles = props.styles,
current = props.current,
vertical = props.vertical,
count = props.count,
dotStyle = props.dotStyle,
dotActiveStyle = props.dotActiveStyle;
var positionStyle = vertical ? 'paginationY' : 'paginationX';
var flexDirection = vertical ? 'column' : 'row';
var arr = [];
for (var i = 0; i < count; i++) {
arr.push(React.createElement(View, { key: 'dot-' + i, style: [styles.pointStyle, styles.spaceStyle, dotStyle, i === current && styles.pointActiveStyle, i === current && dotActiveStyle] }));
}
return React.createElement(
View,
{ style: [styles.pagination, styles[positionStyle]] },
React.createElement(
View,
{ style: { flexDirection: flexDirection } },
arr
)
);
};
var Carousel = function (_React$Component) {
_inherits(Carousel, _React$Component);
function Carousel(props) {
_classCallCheck(this, Carousel);
var _this = _possibleConstructorReturn(this, (Carousel.__proto__ || Object.getPrototypeOf(Carousel)).call(this, props));
_this.loopJump = function () {
// iOS 通过 contentOffet 可以平滑过度,不需要做处理
if (_this.state.loopJump && Platform.OS === 'android') {
var _index = _this.state.selectedIndex + (_this.props.infinite ? 1 : 0);
setTimeout(function () {
var x = _this.state.width * _index;
_this.refs.scrollview.scrollTo({ x: x, y: 0 }, false);
}, 10);
}
};
_this.autoplay = function () {
var _this$props = _this.props,
children = _this$props.children,
autoplay = _this$props.autoplay,
infinite = _this$props.infinite,
autoplayInterval = _this$props.autoplayInterval;
var _this$state = _this.state,
isScrolling = _this$state.isScrolling,
autoplayEnd = _this$state.autoplayEnd,
selectedIndex = _this$state.selectedIndex;
var count = children ? children.length || 1 : 0;
if (!Array.isArray(children) || !autoplay || isScrolling || autoplayEnd) {
return;
}
clearTimeout(_this.autoplayTimer);
_this.autoplayTimer = setTimeout(function () {
if (!infinite && selectedIndex === count - 1) {
// !infinite && last one, autoplay end
return _this.setState({ autoplayEnd: true });
}
_this.scrollNextPage();
}, autoplayInterval);
};
_this.onScrollBegin = function (e) {
_this.setState({
isScrolling: true
}, function () {
if (_this.props.onScrollBeginDrag) {
_this.props.onScrollBeginDrag(e, _this.state, _this);
}
});
};
_this.onScrollEnd = function (e) {
_this.setState({ isScrolling: false });
// android incompatible
if (!e.nativeEvent.contentOffset) {
var position = e.nativeEvent.position;
e.nativeEvent.contentOffset = {
x: position * _this.state.width
};
}
_this.updateIndex(e.nativeEvent.contentOffset);
_this.scrollEndTimter = setTimeout(function () {
_this.autoplay();
_this.loopJump();
if (_this.props.onMomentumScrollEnd) {
_this.props.onMomentumScrollEnd(e, _this.state, _this);
}
});
};
_this.onScrollEndDrag = function (e) {
var _this$state2 = _this.state,
offset = _this$state2.offset,
selectedIndex = _this$state2.selectedIndex;
var previousOffset = offset.x;
var newOffset = e.nativeEvent.x;
var count = _this.props.children ? _this.props.children.length || 1 : 0;
if (previousOffset === newOffset && (selectedIndex === 0 || selectedIndex === count - 1)) {
_this.setState({
isScrolling: false
});
}
};
_this.updateIndex = function (offset) {
var state = _this.state;
var selectedIndex = state.selectedIndex;
var diff = offset.x - state.offset.x;
var step = state.width;
var loopJump = false;
var count = _this.props.children ? _this.props.children.length || 1 : 0;
// Do nothing if offset no change.
if (!diff) {
return;
}
selectedIndex = parseInt(selectedIndex + Math.round(diff / step), 10);
if (_this.props.infinite) {
if (selectedIndex <= -1) {
selectedIndex = count - 1;
offset.x = step * count;
loopJump = true;
} else if (selectedIndex >= count) {
selectedIndex = 0;
offset.x = step;
loopJump = true;
}
}
_this.setState({
selectedIndex: selectedIndex,
offset: offset,
loopJump: loopJump
});
var afterChange = _this.props.afterChange;
if (afterChange) {
afterChange(selectedIndex);
}
};
_this.scrollNextPage = function () {
var _this$props2 = _this.props,
children = _this$props2.children,
infinite = _this$props2.infinite;
var count = children ? children.length || 1 : 0;
if (_this.state.isScrolling || count < 2) {
return;
}
var state = _this.state;
var diff = (infinite ? 1 : 0) + _this.state.selectedIndex + 1;
var x = diff * state.width;
var y = 0;
_this.refs.scrollview.scrollTo({ x: x, y: y });
_this.setState({
isScrolling: true,
autoplayEnd: false
});
// trigger onScrollEnd manually in android
if (Platform.OS === 'android') {
_this.androidScrollEndTimer = setTimeout(function () {
_this.onScrollEnd({
nativeEvent: {
position: diff
}
});
}, 0);
}
};
_this.renderContent = function (pages) {
var others = {
onScrollBeginDrag: _this.onScrollBegin,
onMomentumScrollEnd: _this.onScrollEnd,
onScrollEndDrag: _this.onScrollEndDrag
};
return React.createElement(
ScrollView,
_extends({ ref: 'scrollview' }, _this.props, { horizontal: true, pagingEnabled: true, bounces: !!_this.props.bounces, scrollEventThrottle: 100, removeClippedSubviews: false, automaticallyAdjustContentInsets: false, directionalLockEnabled: true, showsHorizontalScrollIndicator: false, showsVerticalScrollIndicator: false, contentContainerStyle: _this.props.style, contentOffset: _this.state.offset }, others),
pages
);
};
_this.renderDots = function (index) {
var _this$props3 = _this.props,
children = _this$props3.children,
vertical = _this$props3.vertical,
styles = _this$props3.styles,
pagination = _this$props3.pagination,
dotStyle = _this$props3.dotStyle,
dotActiveStyle = _this$props3.dotActiveStyle;
var count = children ? children.length || 1 : 0;
return pagination ? pagination({
styles: styles,
vertical: vertical,
current: index,
count: count,
dotStyle: dotStyle,
dotActiveStyle: dotActiveStyle
}) : null;
};
_this.onLayout = function (e) {
// for horizontal, get width, scollTo
var props = _this.props;
var count = props.children ? props.children.length || 1 : 0;
var selectedIndex = count > 1 ? Math.min(props.selectedIndex, count - 1) : 0;
var width = e.nativeEvent.layout.width;
var offsetX = width * (selectedIndex + (props.infinite ? 1 : 0));
_this.setState({
width: width,
offset: { x: offsetX, y: 0 }
}, function () {
if (Platform.OS === 'android') {
_this.refs.scrollview.scrollTo({ y: 0, x: offsetX }, false);
}
});
};
var _this$props4 = _this.props,
children = _this$props4.children,
selectedIndex = _this$props4.selectedIndex;
var count = children ? children.length || 1 : 0;
var index = count > 1 ? Math.min(selectedIndex, count - 1) : 0;
_this.state = {
width: 0,
isScrolling: false,
autoplayEnd: false,
loopJump: false,
selectedIndex: index,
offset: { x: 0, y: 0 }
};
return _this;
}
_createClass(Carousel, [{
key: 'componentDidMount',
value: function componentDidMount() {
this.autoplay();
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
clearTimeout(this.autoplayTimer);
clearTimeout(this.androidScrollEndTimer);
clearTimeout(this.scrollEndTimter);
}
}, {
key: 'render',
value: function render() {
var state = this.state;
var _props = this.props,
dots = _props.dots,
infinite = _props.infinite,
children = _props.children;
var pages = [];
if (!children) {
return React.createElement(
Text,
{ style: { backgroundColor: 'white' } },
'You are supposed to add children inside Carousel'
);
}
var pageStyle = { width: state.width };
var count = children ? children.length || 1 : 0;
// For make infinite at least count > 1
if (count > 1) {
pages = Object.keys(children);
if (infinite) {
pages.unshift(count - 1 + '');
pages.push('0');
}
pages = pages.map(function (page, i) {
return React.createElement(
View,
{ style: pageStyle, key: i },
children[page]
);
});
} else {
pages = React.createElement(
View,
{ style: pageStyle },
children
);
}
return React.createElement(
View,
{ onLayout: this.onLayout },
this.renderContent(pages),
dots && this.renderDots(this.state.selectedIndex)
);
}
}]);
return Carousel;
}(React.Component);
Carousel.defaultProps = {
bounces: true,
infinite: false,
dots: true,
autoplay: false,
autoplayInterval: 3000,
selectedIndex: 0,
// vertical 目前只实现 pagination,内容 vertical 由于自动高度拿不到,暂时无法实现
vertical: false,
styles: CarouselStyle,
pagination: defaultPagination,
dotStyle: {},
dotActiveStyle: {}
};
export default Carousel;