UNPKG

weex-nuke

Version:

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

416 lines (370 loc) 15.4 kB
/** @jsx createElement */ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 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 _nukeEpUtils = require('../../EpUtils/index.js'); var _nukeThemeProvider = require('../../ThemeProvider/index.js'); var _emitter = require('../util/emitter.js'); var _emitter2 = _interopRequireDefault(_emitter); var _index = require('../styles/index.js'); var _index2 = _interopRequireDefault(_index); var _nav = require('./nav.js'); var _nav2 = _interopRequireDefault(_nav); 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; } // 在weex及非android4.4以下的机器中才使用ep绑定 var expressionBinding = {}; try { expressionBinding = require('@weex-module/expressionBinding'); } catch (e) {} var Tabbar = function (_Component) { _inherits(Tabbar, _Component); function Tabbar(props) { _classCallCheck(this, Tabbar); var _this = _possibleConstructorReturn(this, (Tabbar.__proto__ || Object.getPrototypeOf(Tabbar)).call(this, props)); _this.bindExp = function (element) { if (!_this.isMoving && element && element.ref && _nukeEpUtils.Detection.epEnable) { _this.startTime = Date.now(); var _this$props = _this.props, dataSource = _this$props.dataSource, navFocusStyle = _this$props.navFocusStyle; var listElement = (0, _rax.findDOMNode)(_this.refs.listSlider); var index = _this.state.curIndex; var tabFocusElement = (0, _rax.findDOMNode)(_this.refs.nav.wrappedInstance.refs.tabFocus); // 绑定滚动只取第一个 itemWidthList的宽度 var tabItemWidth = dataSource[0] && dataSource[0].style && dataSource[0].style.width; var dpr = 1; var tabLeft = index * tabItemWidth / dpr; if (navFocusStyle && navFocusStyle.left) { // tabLeft += navFocusStyle.left; } var sliderLeft = index * 750 / dpr; /* ep表达式备注 左边界 min(x, x/3) 右边界 max(x, x/3) - ${dist} 中间 x - dist */ var args = [{ element: tabFocusElement.ref, property: 'transform.translateX', expression: '{"type":"-","children":[{"type":"NumericLiteral","value":' + tabLeft + '},{"type":"/","children":[{"type":"Identifier","value":"x"},{"type":"NumericLiteral","value":5}]}]}' }]; if (index == 0) { // 第一帧 min(x, x/3) var ep2 = '{"type":"CallExpression","children":[{"type":"Identifier","value":"min"},{"type":"Arguments","children":[{"type":"Identifier","value":"x"},{"type":"/","children":[{"type":"Identifier","value":"x"},{"type":"NumericLiteral","value":3}]}]}]}'; args.push({ element: listElement.ref, property: 'transform.translateX', expression: ep2 }); } else if (index == dataSource.length - 1) { // 最后一祯 `max(x, x/3) - ${sliderLeft}` var _ep = '{"type":"-","children":[{"type":"CallExpression","children":[{"type":"Identifier","value":"max"},{"type":"Arguments","children":[{"type":"Identifier","value":"x"},{"type":"/","children":[{"type":"Identifier","value":"x"},{"type":"NumericLiteral","value":3}]}]}]},{"type":"NumericLiteral","value":' + sliderLeft + '}]}'; args.push({ element: listElement.ref, property: 'transform.translateX', expression: _ep }); } else { // `x - ${sliderLeft}` var _ep2 = '{"type":"-","children":[{"type":"Identifier","value":"x"},{"type":"NumericLiteral","value":' + sliderLeft + '}]}'; args.push({ element: listElement.ref, property: 'transform.translateX', expression: _ep2 }); } // console.log('enableBinding'); // expressionBinding.enableBinding(element.ref, 'pan'); // console.log('createBinding'); expressionBinding.createBinding(element.ref, 'pan', '', args, _this.panEnd); } }; _this.onHorizontalPan = function (e) { if (e.state === 'start' && !_this.scrolling) { var listElement = (0, _rax.findDOMNode)(_this.refs.listSlider); _this.bindExp(listElement); } }; _this.panEnd = function (e) { console.log('[debug]:panEnd'); if (e.state === 'end') { var duration = Date.now() - _this.startTime; var dist = e.deltaX; var curIndex = _this.state.curIndex; var panDist = _this.props.panDist ? _this.props.panDist : 375; var newIndex = curIndex; if (Math.abs(dist) > panDist || Math.abs(dist) / duration > 0.5 && duration < 200) { if (dist > 0) { newIndex--; } else { newIndex++; } } if (newIndex < 0) { newIndex = 0; } else if (newIndex > _this.maxIndex) { newIndex = _this.maxIndex; } if (_nukeEpUtils.Detection.iOS) { setTimeout(function () { _this.slideTo(newIndex, 'pan'); }, 50); } else { _this.slideTo(newIndex, 'pan'); } } }; _this.slideTo = function (index, type) { var time = 300; if (_this.isMoving === true) return; _this.isMoving = true; var _this$props2 = _this.props, onChange = _this$props2.onChange, beforeSlide = _this$props2.beforeSlide, forbidNavScroll = _this$props2.forbidNavScroll; var prevIndex = _this.state.curIndex; var moveEndCallback = function moveEndCallback() { if (typeof onChange === 'function') { onChange(index, prevIndex, type); } _this.setState({ curIndex: index, prevIndex: prevIndex }); _this.isMoving = false; }; var navRef = _this.refs.nav && _this.refs.nav.wrappedInstance; if (typeof beforeSlide === 'function') { if (!beforeSlide(index, type)) return; } // 选中状态滚动,当只有两个item,无需scroll的时候需要禁止滚动 if (!forbidNavScroll) { navRef.scrollTo(index); } navRef.focusMove(index); navRef.setState({ curIndex: index }); if (_nukeEpUtils.Detection.epEnable) { // 高版本系统的手机才使用transform动画 var animation = require('@weex-module/animation'); var sliderElement = _this.refs.listSlider; var dist = 750 * index; animation.transition((0, _rax.findDOMNode)(sliderElement), { styles: { transform: 'translateX(-' + dist + 'px)' }, delay: 0, duration: time, timingFunction: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)' // ['cubic-bezier(0.25, 0.46, 0.45, 0.94)', 'cubic-bezier(0,0,0.25,1)'] }, function () {}); } moveEndCallback(); }; _this.childrenElements = []; // 存放tab主体element _this.tabMap = {}; // 用于记录哪个tab是被激活过的状态 _this.tabPage = []; // 存放tab节点 _this.scrolling = false; _this.maxIndex = props.children && props.children.length - 1 || 0; // tab的子节点只能是tab.item _this.state = { curIndex: props.activeKey && props.activeKey >= 0 && props.activeKey <= _this.maxIndex ? props.active : 0, transform: 0, prevIndex: null }; if (typeof props.activeKey === 'number' && props.activeKey >= 0 && props.activeKey <= _this.maxIndex) { _this.tabMap[props.activeKey] = true; } return _this; } _createClass(Tabbar, [{ key: 'componentWillMount', value: function componentWillMount() { var _this2 = this; _emitter2.default.on('scroll', function (data) { _this2.scrolling = true; if (_this2.scrollTimer) { clearTimeout(_this2.scrollTimer); } _this2.scrollTimer = setTimeout(function () { _this2.scrolling = false; }, 300); }); } }, { key: 'componentDidMount', value: function componentDidMount() { var _this3 = this; if (_nukeEpUtils.Detection.epEnable && _nukeEpUtils.Detection.iOS && this.props.epEnable) { setTimeout(function () { var listElement = (0, _rax.findDOMNode)(_this3.refs.listSlider); if (listElement && listElement.ref) { expressionBinding.enableBinding(listElement.ref, 'pan'); } }, 500); } // hack for android if (_nukeEpUtils.Detection.epEnable && _nukeEpUtils.Detection.Android) { _emitter2.default.on('slider', function (params) { _this3.bindExp(params.element); }); } } /** * ep绑定方法 */ /** * 横向滑动事件 */ /** * 横向滑动停止 */ /** * tab切换前的回调函数 * @param index 即将滚动去的位置 * @param type 触发滚动的事件类型 */ }, { key: 'render', value: function render() { var _this4 = this; var _state = this.state, curIndex = _state.curIndex, prevIndex = _state.prevIndex; var _props = this.props, themeStyle = _props.themeStyle, children = _props.children, style = _props.style, navTop = _props.navTop, dataSource = _props.dataSource, renderNavItem = _props.renderNavItem, navStyle = _props.navStyle, renderLoading = _props.renderLoading, navFocusStyle = _props.navFocusStyle, forceRender = _props.forceRender, navContentStyle = _props.navContentStyle; var slider = themeStyle.slider; if (!children.length) { return null; } if (navTop) { slider.top = navStyle && navStyle.height; navStyle.top = 0; delete navStyle.bottom; } else { slider.bottom = navStyle && navStyle.height; navStyle.bottom = 0; delete navStyle.top; } // 根据子节点计算tab偏移 var sliderStyle = [slider]; if (_nukeEpUtils.Detection.epEnable) { sliderStyle.push({ width: 750 * children.length }); if (_nukeEpUtils.Detection.iOS) { sliderStyle.push({ transform: 'translateX(-' + 750 * this.state.curIndex + ')' }); } if (this.tabMap[curIndex]) { this.tabMap[curIndex]++; } else { this.tabMap[curIndex] = 1; } } var formatChildren = []; if (_nukeEpUtils.Detection.epEnable) { formatChildren = children.map(function (child, index) { var length = children.length; var next = circleIndex(_this4.state.curIndex + 1, length); var prev = circleIndex(_this4.state.curIndex - 1, length); var shouldRender = _this4.tabMap[index] === 1; var eachTabStyle = [themeStyle.eachTab, { left: 750 * index }]; if (_this4.tabMap[index] && curIndex === index) { _this4.tabPage[curIndex] = (0, _rax.createElement)( _nukeView2.default, { style: eachTabStyle, key: index, shouldRender: shouldRender }, child ); } if (_this4.tabMap[index]) { return _this4.tabPage[index]; } if (typeof renderLoading === 'function' && (index === next || index === prev)) { return (0, _rax.createElement)( _nukeView2.default, { style: eachTabStyle, key: index }, renderLoading(index) ); } return null; }); } else { formatChildren = children.map(function (child, index) { if (index === curIndex) { return child; } return null; }); } var childrenElements = [(0, _rax.createElement)( _nukeView2.default, { style: sliderStyle, ref: 'listSlider', onHorizontalPan: _nukeEpUtils.Detection.epEnable && _nukeEpUtils.Detection.iOS && this.props.epEnable ? this.onHorizontalPan : null }, formatChildren )]; var headerStyle = navTop ? _extends({}, navStyle, { top: 0, positon: 'relative' }) : navStyle; var NavWithProps = (0, _rax.createElement)( _nukeView2.default, { style: [themeStyle.header, headerStyle] }, (0, _rax.createElement)(_nav2.default, { ref: 'nav', dataSource: dataSource, renderNavItem: renderNavItem, slideTo: function slideTo() { return _this4.slideTo.apply(_this4, arguments); }, style: navStyle, contentStyle: navContentStyle, navFocusStyle: navFocusStyle, forceRender: forceRender }) ); navTop ? childrenElements.unshift(NavWithProps) : childrenElements.push(NavWithProps); return (0, _rax.createElement)( _nukeView2.default, { style: [themeStyle.wrapContainer, style] }, childrenElements ); } }]); return Tabbar; }(_rax.Component); function circleIndex(i, len) { return (len + i % len) % len; } // Tabbar.propTypes = { // }; Tabbar.defaultProps = { epEnable: false, navTop: true }; Tabbar.displayName = 'Ep-Tabbar'; exports.default = (0, _nukeThemeProvider.connectStyle)(_index2.default)(Tabbar); module.exports = exports['default'];