UNPKG

weex-nuke

Version:

基于 Rax 、Weex 的高性能组件体系 ~~

510 lines (432 loc) 15.9 kB
/* @jsx createElement */ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = undefined; 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 _rax = require('rax'); var _nukeView = require('../View/index.js'); var _nukeView2 = _interopRequireDefault(_nukeView); var _nukeSwipe = require('../Swipe/index.js'); var _nukeSwipe2 = _interopRequireDefault(_nukeSwipe); var _defaultStyle = require('./defaultStyle.js'); var _defaultStyle2 = _interopRequireDefault(_defaultStyle); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: 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 propTypes = { onChange: _rax.PropTypes.func, paginationStyle: _rax.PropTypes.object }; /** * @Slider Entrance * rx-slider h5 version **/ var Slide = function (_Component) { _inherits(Slide, _Component); function Slide(props) { _classCallCheck(this, Slide); var _this = _possibleConstructorReturn(this, (Slide.__proto__ || Object.getPrototypeOf(Slide)).call(this, props)); _this.state = { isSwiping: false, offsetX: '', loopIdx: 0 }; return _this; } _createClass(Slide, [{ key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { var initState = this.state; initState.total = nextProps.children ? nextProps.children.length || 1 : 0; initState.index = initState.total > 1 ? Math.min(nextProps.index, initState.total - 1) : 0; initState.height = nextProps.height; initState.width = parseFloat(nextProps.width) * document.documentElement.clientWidth / 750; // 新增默认偏移量 initState.offsetX = initState.index * initState.width; // 新增默认参数 initState.loopIdx = initState.index; if (initState.total > 1) { var setup = nextProps.loop ? 1 : initState.index; } this.setState(initState); } }, { key: 'componentWillMount', value: function componentWillMount() { var initState = this.state; initState.total = this.props.children ? this.props.children.length || 1 : 0; initState.index = initState.total > 1 ? Math.min(this.props.index, initState.total - 1) : 0; initState.height = this.props.height; initState.width = parseFloat(this.props.width) * document.documentElement.clientWidth / 750; // 新增默认偏移量 initState.offsetX = initState.index * initState.width; // 新增默认参数 initState.loopIdx = initState.index; if (initState.total > 1) { var setup = this.props.loop ? 1 : initState.index; } this.setState(initState); } }, { key: 'componentDidMount', value: function componentDidMount() { if (this.state.total < 2) { return; } else { var x = this.state.index * this.state.width; this.changeOffset(x, this.state.index); } this.autoPlay(); } }, { key: 'autoPlay', value: function autoPlay() { var that = this; // 非自动播放的情况 return 掉 if (!Array.isArray(this.props.children) || !this.props.autoPlay || this.state.isSwiping) { return; } clearTimeout(this.autoPlayTimer); this.autoPlayTimer = setTimeout(function () { // let toIndex = that.state.total > that.state.index + 1 ? that.state.index + 1 : 0; that.slideTo(); }, parseFloat(this.props.autoplayInterval)); } }, { key: 'slideTo', value: function slideTo(index) { var that = this; var state = this.state; if (state.isSwiping || state.total < 2) { return; } // 非传入指定 index 的情况 var noIndex = typeof index === 'undefined'; var diff = noIndex ? state.index : index; var x = diff * state.width; //根据index和偏移改变位置 this.changeOffset(x, diff); if (noIndex) { // 自加index this.updateIndex(); } else { this.setState({ index: diff }); } //开启下一轮播放 this.setAutoTimer(); } }, { key: 'setAutoTimer', value: function setAutoTimer() { var that = this; clearTimeout(this.autoTimer); this.autoTimer = setTimeout(function () { that.autoPlay(); }, 0); } // 改变 slider 的框子位置 }, { key: 'changeOffset', value: function changeOffset(x, idx, distance) { // console.log('change', x, idx) var state = this.state, width = state.width; if (!this.refs.swipeView) { return; } // 外框translate3d for translate3d 为了性能 var swipeView = (0, _rax.findDOMNode)(this.refs.swipeView); swipeView.style.transform = 'translate3d(' + -x + 'px, 0px, 0px)'; swipeView.style.webkitTransform = 'translate3d(' + -x + 'px, 0px, 0px)'; var len = this.props.children.length; idx = this.loopedIndex(idx, len); this.setState({ loopIdx: idx, offsetX: x }); // 内层child changeleft this.changeChildPosition(idx, x); // 确保当前页的前后页都已经具备了 if (state.total < 3) { return; } if (distance && distance < 0) { idx = this.loopedIndex(idx + 1, len); this.changeChildPosition(idx, x + width); } else if (distance && distance > 0) { idx = this.loopedIndex(idx - 1, len); this.changeChildPosition(idx, x - width); } } // 改变子元素位置 }, { key: 'changeChildPosition', value: function changeChildPosition(idx, offset) { if (idx < 0 || idx > this.props.children.length) { return; } var childNum = 'child' + idx; var childView = (0, _rax.findDOMNode)(this.refs[childNum]); childView.style.left = offset + 'px'; } }, { key: 'renderSwipeView', value: function renderSwipeView(pages) { var state = this.state; var style = { width: state.width + 'px', height: state.height }; return state.total > 1 ? (0, _rax.createElement)( _nukeSwipe2.default, { style: [_defaultStyle2.default.swipeWrapper, style], onSwipeBegin: this.onSwipeBegin.bind(this), onSwipeEnd: this.onSwipeEnd.bind(this), onSwipe: this.onSwipe.bind(this), initialVelocityThreshold: this.props.initialVelocityThreshold, verticalThreshold: this.props.verticalThreshold, vertical: this.props.vertical, horizontalThreshold: this.props.horizontalThreshold }, (0, _rax.createElement)( _nukeView2.default, { ref: 'swipeView', style: [_defaultStyle2.default.swipeStyle, style] }, pages ) ) : (0, _rax.createElement)( _nukeView2.default, { ref: 'swipeView', style: [_defaultStyle2.default.swipeStyle, style] }, pages ); } }, { key: 'onSwipeBegin', value: function onSwipeBegin(_ref) { var direction = _ref.direction, distance = _ref.distance, velocity = _ref.velocity; this.setState({ isSwiping: true }); // 手势翻页时暂定自动翻页 clearTimeout(this.autoTimer); } }, { key: 'onSwipe', value: function onSwipe(_ref2) { var direction = _ref2.direction, distance = _ref2.distance, velocity = _ref2.velocity; var index = this.state.index, width = this.state.width, x = this.state.offsetX, num = this.props.children.length, idx = index; if (!this.props.loop && (index === num - 1 || index === 0)) { return; } var changeX = 0; if (distance < 0) { changeX = -(x + Math.abs(distance)); } else { changeX = -(x - Math.abs(distance)); } var swipeView = (0, _rax.findDOMNode)(this.refs.swipeView); swipeView.style.transform = 'translate3d(' + changeX + 'px, 0px, 0px)'; swipeView.style.webkitTransform = 'translate3d(' + changeX + 'px, 0px, 0px)'; } }, { key: 'onSwipeEnd', value: function onSwipeEnd(_ref3) { var direction = _ref3.direction, distance = _ref3.distance, velocity = _ref3.velocity; // 更加流畅的翻页体验 TODO this.setState({ isSwiping: true }); this.updateIndex(distance); } }, { key: 'updateIndex', value: function updateIndex(distance) { var onChange = this.props.onChange; var that = this; var state = this.state, index = state.index, step = state.width, num = this.props.children.length; index = this.changeIndex(distance, index, num); // fix 左滑index为负数 var idx = distance ? this.loopedIndex(index, num) : this.loopedIndex(index - 1, num); // 暴露index onChange && onChange({ index: idx }); this.setState({ index: index }); // 手势改变改变位置 if (distance) { var x = index * state.width; this.changeOffset(x, index, distance); this.setState({ isSwiping: false }); // 手势翻页结束后基于当前index继续轮播 this.setAutoTimer(); } } // 循环改变index (自增、自减) }, { key: 'changeIndex', value: function changeIndex(distance, index, num) { if (this.props.loop) { if (distance && distance > 0) { index = index - 1; } else { index = index + 1; } } else if (!this.props.loop) { if (distance && distance > 0 && index !== 0) { index = index - 1; } else if (distance && distance < 0 && index !== num - 1) { index = index + 1; } else { return index; } } return index; } // 使index维持在0-length之间循环 }, { key: 'loopedIndex', value: function loopedIndex(idx, len) { // console.log(idx, len) if (idx > 0 && idx >= len - 1) { idx = idx % len; } else if (idx < 0 && idx <= -(len + 1)) { idx = idx % len; idx = idx === 0 ? 0 : idx + len; } else if (idx < 0 && idx >= -(len + 1)) { idx = idx + len; } return idx; } }, { key: 'renderPagination', value: function renderPagination() { var props = this.props; if (this.state.total <= 1) { return; } var itemSelectedColor = void 0, itemColor = void 0, itemSize = void 0; if (props.paginationStyle) { itemSelectedColor = props.paginationStyle.itemSelectedColor || _defaultStyle2.default.defaultPaginationStyle.itemSelectedColor; itemColor = props.paginationStyle.itemColor || _defaultStyle2.default.defaultPaginationStyle.itemColor; itemSize = props.paginationStyle.itemSize || _defaultStyle2.default.defaultPaginationStyle.itemSize; } var activeStyle = [_defaultStyle2.default.activeDot, { backgroundColor: itemSelectedColor, width: itemSize, height: itemSize, borderRadius: itemSize }]; var normalStyle = [_defaultStyle2.default.normalDot, { backgroundColor: itemColor, width: itemSize, height: itemSize, borderRadius: itemSize }]; var dots = []; var ActiveDot = this.props.activeDot || (0, _rax.createElement)(_nukeView2.default, { style: activeStyle }); var NormalDot = this.props.normalDot || (0, _rax.createElement)(_nukeView2.default, { style: normalStyle }); var activeIndex = this.state.loopIdx; for (var i = 0; i < this.state.total; i++) { dots.push(i === activeIndex ? (0, _rax.cloneElement)(ActiveDot, { key: i }) : (0, _rax.cloneElement)(NormalDot, { key: i })); } return (0, _rax.createElement)( _nukeView2.default, { style: [_defaultStyle2.default.defaultPaginationStyle, props.paginationStyle ? props.paginationStyle : ''] }, dots ); } }, { key: 'getPages', value: function getPages() { var _this2 = this; var state = this.state, props = this.props, children = props.children, index = state.index; var pages = []; if (state.total > 1) { children.forEach(function (child, i) { var refStr = 'child' + i; var translateStyle = { width: state.width + 'px', height: state.height, left: i * state.width + 'px' }; pages.push((0, _rax.createElement)( _nukeView2.default, { ref: refStr, className: 'childWrap' + i, style: [_defaultStyle2.default.childrenStyle, translateStyle], key: i }, _this2.getChild(i, child) )); }); } else { pages = (0, _rax.createElement)( _nukeView2.default, { style: _defaultStyle2.default.childrenStyle }, children ); } return pages; } // 只渲染当前index前后两页 for 性能 // TODO 是否有必要删除已经浏览过的page }, { key: 'getChild', value: function getChild(i, child) { var that = this, index = this.state.index, len = this.props.children.length; // 自动翻页时确保翻页之前的当前页的前后结点,防止翻页空白 if (this.props.autoPlay) { index = index - 1; } index = this.loopedIndex(index, len); var left = this.loopedIndex(index - 1, len), right = this.loopedIndex(index + 1, len); if (i === index || i === left || i === right) { return child; } } }, { key: 'render', value: function render() { var that = this; return (0, _rax.createElement)( _nukeView2.default, { style: [_defaultStyle2.default.slideWrapper, this.props.style] }, this.renderSwipeView(that.getPages()), this.props.showsPagination ? this.renderPagination() : '' ); } }]); return Slide; }(_rax.Component); exports.default = Slide; ; Slide.defaultProps = { horizontal: true, showsPagination: true, loop: true, autoPlay: false, autoplayInterval: 3000, index: 0, paginationStyle: null, initialVelocityThreshold: 0.7, verticalThreshold: 10, horizontalThreshold: 10, vertical: false }; Slide.propTypes = propTypes; module.exports = exports['default'];