UNPKG

bdyl-pull-to-refresh

Version:

React Mobile Pull To Refresh Component

376 lines (345 loc) 15.5 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var __rest = undefined && undefined.__rest || function (s, e) { var t = {}; for (var p in s) { if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; }if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; }return t; }; var StaticRenderer = function (_React$Component) { (0, _inherits3['default'])(StaticRenderer, _React$Component); function StaticRenderer() { (0, _classCallCheck3['default'])(this, StaticRenderer); return (0, _possibleConstructorReturn3['default'])(this, (StaticRenderer.__proto__ || Object.getPrototypeOf(StaticRenderer)).apply(this, arguments)); } (0, _createClass3['default'])(StaticRenderer, [{ key: 'shouldComponentUpdate', value: function shouldComponentUpdate(nextProps) { return nextProps.shouldUpdate; } }, { key: 'render', value: function render() { return _react2['default'].createElement( 'div', null, this.props.render() ); } }]); return StaticRenderer; }(_react2['default'].Component); function setTransform(nodeStyle, value) { nodeStyle.transform = value; nodeStyle.webkitTransform = value; nodeStyle.MozTransform = value; } var isWebView = typeof navigator !== 'undefined' && /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent); var DOWN = 'down'; var UP = 'up'; var UP_DOWN = 'up_down'; var INDICATOR = { activate: 'release', deactivate: 'pull', release: _react2['default'].createElement('div', { className: 'bdyl-pull-to-refresh-indicator-loading' }), finish: 'finish' }; var supportsPassive = false; try { var opts = Object.defineProperty({}, 'passive', { get: function get() { supportsPassive = true; } }); window.addEventListener('test', null, opts); } catch (e) { // empty } var willPreventDefault = supportsPassive ? { passive: false } : false; // const willNotPreventDefault = supportsPassive ? { passive: true } : false; var PullToRefresh = function (_React$Component2) { (0, _inherits3['default'])(PullToRefresh, _React$Component2); function PullToRefresh(props) { (0, _classCallCheck3['default'])(this, PullToRefresh); var _this2 = (0, _possibleConstructorReturn3['default'])(this, (PullToRefresh.__proto__ || Object.getPrototypeOf(PullToRefresh)).call(this, props)); _this2.shouldUpdateChildren = false; _this2.triggerPullToRefresh = function (direction) { // 在初始化时、用代码 自动 触发 pullToRefresh // 注意:当 direction 为 up 时,当 visible length < content length 时、则看不到效果 if (!_this2.state.dragOnEdge) { if (_this2.props.refreshing) { if (direction === UP) { _this2._lastScreenY = -_this2.props.distanceToRefresh - 1; } if (direction === DOWN) { _this2._lastScreenY = _this2.props.distanceToRefresh + 1; } // change dom need after setState _this2.setState({ currSt: 'release' }, function () { return _this2.setContentStyle(_this2._lastScreenY); }); } else { _this2.setState({ currSt: 'finish' }, function () { return _this2.reset(); }); } } }; _this2.init = function (ele) { if (!ele) { // like return in destroy fn ???!! return; } _this2._to = { touchstart: _this2.onTouchStart.bind(_this2, ele), touchmove: _this2.onTouchMove.bind(_this2, ele), touchend: _this2.onTouchEnd.bind(_this2, ele), touchcancel: _this2.onTouchEnd.bind(_this2, ele) }; Object.keys(_this2._to).forEach(function (key) { ele.addEventListener(key, _this2._to[key], willPreventDefault); }); }; _this2.destroy = function (ele) { if (!_this2._to || !ele) { // componentWillUnmount fire before componentDidMount, like forceUpdate ???!! return; } Object.keys(_this2._to).forEach(function (key) { ele.removeEventListener(key, _this2._to[key]); }); }; _this2.onTouchStart = function (_ele, e) { _this2._ScreenY = _this2._startScreenY = e.touches[0].screenY; // 一开始 refreshing 为 true 时 this._lastScreenY 有值 _this2._lastScreenY = _this2._lastScreenY || 0; }; _this2.isEdge = function (ele, direction) { var container = _this2.props.getScrollContainer(); if (container && container === document.body) { // In chrome61 `document.body.scrollTop` is invalid var scrollNode = document.scrollingElement ? document.scrollingElement : document.body; if (direction === UP) { return scrollNode.scrollHeight - scrollNode.scrollTop <= window.innerHeight; } if (direction === DOWN) { return scrollNode.scrollTop <= 0; } } // console.log(ele.scrollTop); // console.log(ele.scrollHeight) if (direction === UP) { return ele.scrollHeight - ele.scrollTop === ele.clientHeight; } if (direction === DOWN) { return ele.scrollTop <= 0; } }; _this2.onTouchMove = function (ele, e) { // if(this.props.refreshing) { // return; // } // 使用 pageY 对比有问题 var _screenY = e.touches[0].screenY; if (_this2.props.direction === UP_DOWN) { // if props.direction = up_down, auto detect direction when ontouchmove _this2._direction = _this2._startScreenY > _screenY ? UP : DOWN; } else { // 拖动方向不符合的不处理 _this2._direction = _this2.props.direction; if (_this2._direction === UP && _this2._startScreenY < _screenY || _this2._direction === DOWN && _this2._startScreenY > _screenY) { return; } } if (_this2.isEdge(ele, _this2._direction)) { //如果正在刷新中,则不可上拉刷新或者下拉刷新 if (_this2.props.refreshing) { return; } if (!_this2.state.dragOnEdge) { _this2.setState({ dragOnEdge: true }); } e.preventDefault(); // add stopPropagation with fastclick will trigger content onClick event. why? // ref https://github.com/ant-design/ant-design-mobile/issues/2141 // e.stopPropagation(); var _diff = Math.round(_screenY - _this2._ScreenY); _this2._ScreenY = _screenY; _this2._lastScreenY += _diff; // console.log('diff',_diff); // console.log('_screenY',_screenY); // console.log('_lastSreenY', this._lastScreenY); _this2.setContentStyle(_this2._lastScreenY); if (Math.abs(_this2._lastScreenY) < _this2.props.distanceToRefresh) { if (_this2.state.currSt !== 'deactivate') { //console.log('back to the distance'); _this2.setState({ currSt: 'deactivate' }); } } else { if (_this2.state.currSt === 'deactivate') { //console.log('reach to the distance'); _this2.setState({ currSt: 'activate' }); } } // https://github.com/ant-design/ant-design-mobile/issues/573#issuecomment-339560829 // iOS UIWebView issue, It seems no problem in WKWebView if (isWebView && e.changedTouches[0].clientY < 0) { _this2.onTouchEnd(); } } }; _this2.onTouchEnd = function () { if (_this2.state.dragOnEdge) { _this2.setState({ dragOnEdge: false }); } if (_this2.state.currSt === 'activate') { _this2.setState({ currSt: 'release' }); _this2._timer = setTimeout(function () { if (!_this2.props.refreshing) { _this2.setState({ currSt: 'finish' }, function () { return _this2.reset(); }); } _this2._timer = undefined; }, _this2.props.minTime || 1000); _this2.props.onRefresh(_this2._direction); } else { _this2.reset(); } }; _this2.reset = function () { _this2._lastScreenY = 0; _this2.setContentStyle(0); }; _this2.setContentStyle = function (ty) { // todos: Why sometimes do not have `this.contentRef` ? if (_this2.props.maxTranslate) { if (Math.abs(ty) >= _this2.props.maxTranslate) { return; } } if (_this2.contentRef) { setTransform(_this2.contentRef.style, 'translate3d(0px,' + ty + 'px,0)'); } }; var direction = props.direction; // https://github.com/yiminghe/zscroller/blob/2d97973287135745818a0537712235a39a6a62a1/src/Scroller.js#L355 // currSt: `activate` / `deactivate` / `release` / `finish` _this2.state = { currSt: '', dragOnEdge: false }; _this2._direction = direction === UP_DOWN ? DOWN : direction; return _this2; } (0, _createClass3['default'])(PullToRefresh, [{ key: 'shouldComponentUpdate', value: function shouldComponentUpdate(nextProps) { this.shouldUpdateChildren = this.props.children !== nextProps.children; return true; } }, { key: 'componentDidUpdate', value: function componentDidUpdate(prevProps) { if (prevProps === this.props || prevProps.refreshing === this.props.refreshing) { return; } // triggerPullToRefresh 需要尽可能减少 setState 次数 this.triggerPullToRefresh(this._direction); } }, { key: 'componentDidMount', value: function componentDidMount() { var _this3 = this; // `getScrollContainer` most likely return React.Node at the next tick. Need setTimeout setTimeout(function () { _this3.init(_this3.props.getScrollContainer() || _this3.containerRef); _this3.triggerPullToRefresh(_this3._direction); }); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { // Should have no setTimeout here! this.destroy(this.props.getScrollContainer() || this.containerRef); } }, { key: 'render', value: function render() { var _this4 = this; var _a = this.props, className = _a.className, prefixCls = _a.prefixCls, children = _a.children, getScrollContainer = _a.getScrollContainer, onRefresh = _a.onRefresh, refreshing = _a.refreshing, indicator = _a.indicator, distanceToRefresh = _a.distanceToRefresh, restProps = __rest(_a, ["className", "prefixCls", "children", "getScrollContainer", "onRefresh", "refreshing", "indicator", "distanceToRefresh"]); var renderChildren = _react2['default'].createElement(StaticRenderer, { shouldUpdate: this.shouldUpdateChildren, render: function render() { return children; } }); var renderRefresh = function renderRefresh(cls) { var cla = (0, _classnames2['default'])(cls, !_this4.state.dragOnEdge && prefixCls + '-transition'); return _react2['default'].createElement( 'div', { className: prefixCls + '-content-wrapper' }, _react2['default'].createElement( 'div', { className: cla, ref: function ref(el) { return _this4.contentRef = el; } }, _react2['default'].createElement( 'div', { className: prefixCls + '-indicator' }, indicator[_this4.state.currSt] || INDICATOR[_this4.state.currSt] ), renderChildren ) ); }; if (getScrollContainer()) { return renderRefresh(prefixCls + '-content ' + prefixCls + '-' + this._direction); } return _react2['default'].createElement( 'div', (0, _extends3['default'])({ ref: function ref(el) { return _this4.containerRef = el; }, className: (0, _classnames2['default'])(className, prefixCls, prefixCls + '-' + this._direction) }, restProps), renderRefresh(prefixCls + '-content') ); } }]); return PullToRefresh; }(_react2['default'].Component); exports['default'] = PullToRefresh; PullToRefresh.defaultProps = { prefixCls: 'bdyl-pull-to-refresh', getScrollContainer: function getScrollContainer() { return undefined; }, direction: DOWN, distanceToRefresh: 40, indicator: INDICATOR }; module.exports = exports['default'];