weex-nuke
Version:
基于 Rax 、Weex 的高性能组件体系 ~~
510 lines (432 loc) • 15.9 kB
JavaScript
/* @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'];