UNPKG

@jdcfe/yep-react

Version:

一套移动端的React组件库

251 lines (220 loc) 8.72 kB
import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized"; import _inherits from "@babel/runtime/helpers/inherits"; import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf"; function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } import * as React from 'react'; import { setTransform } from '../_utils/styleUtil'; var INDICATOR = { activate: '释放更新', deactivate: '下拉刷新', release: '加载中...', finish: '完成' }; var PullToRefresh = /*#__PURE__*/function (_React$PureComponent) { _inherits(PullToRefresh, _React$PureComponent); var _super = _createSuper(PullToRefresh); function PullToRefresh(props) { var _this; _classCallCheck(this, PullToRefresh); _this = _super.call(this, props); _this.containerRef = function (container) { _this.container = container; }; _this.triggerPullToRefresh = function () { if (_this.props.refreshing) { // change dom need after setState _this.setState({ currentState: 'release' }, function () { return _this.setInfScrollStyle(_this.props.pullDownToRefreshThreshold + 1); }); } else { _this.setState({ currentState: 'finish' }, function () { return _this.reset(); }); } }; _this.isMoveEdge = function () { var container = _this.props.getScrollContainer(); if (container && container === document.body) { var scrollNode = document.scrollingElement ? document.scrollingElement : document.body; return scrollNode.scrollTop <= 0; } var refScrollTop = container && container.scrollTop || 0; var tops = [window.pageYOffset || 0, document.documentElement.scrollTop, refScrollTop]; return Math.max.apply(Math, tops) <= 0; }; _this.setInfScrollStyle = function (cs) { if (_this.container) { setTransform(_this.container.style, "translate3d(0px,".concat(cs, "px,0)")); } }; _this.reset = function () { _this.setInfScrollStyle(0); requestAnimationFrame(function () { _this.container.style.overflow = 'auto'; _this.container.style.transform = 'none'; _this.container.style.willChange = 'none'; }); }; _this.state = { currentState: 'deactivate' }; // variables to keep track of pull down behaviour _this.startY = 0; _this.startX = 0; _this.currentY = 0; _this.currentX = 0; _this.dragging = false; // will be populated in componentDidMount // based on the height of the pull down element _this.onStart = _this.onStart.bind(_assertThisInitialized(_this)); _this.onMove = _this.onMove.bind(_assertThisInitialized(_this)); _this.onEnd = _this.onEnd.bind(_assertThisInitialized(_this)); return _this; } _createClass(PullToRefresh, [{ key: "componentDidMount", value: function componentDidMount() { this.ele = this.props.getScrollContainer() || this.container; this.ele.addEventListener('touchstart', this.onStart, { passive: false }); this.ele.addEventListener('touchmove', this.onMove, { passive: false }); this.ele.addEventListener('touchend', this.onEnd, { passive: false }); this.forceUpdate(); if (typeof this.props.refreshFunction !== 'function') { throw new Error("Mandatory prop \"refreshFunction\" missing.\n Pull Down To Refresh functionality will not work\n as expected.'"); } } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { if (prevProps === this.props || prevProps.refreshing === this.props.refreshing) { return; } this.triggerPullToRefresh(); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.ele.removeEventListener('touchstart', this.onStart); this.ele.removeEventListener('touchmove', this.onMove); this.ele.removeEventListener('touchend', this.onEnd); } }, { key: "onStart", value: function onStart(evt) { this.dragging = true; this.startY = evt.pageY || evt.touches[0].pageY; this.startX = evt.pageX || evt.touches[0].pageX; this.currentY = this.startY; this.currentX = this.startX; this.container.style.willChange = 'transform'; this.container.style.transition = "transform 0.2s cubic-bezier(0,0,0.31,1)"; } }, { key: "onMove", value: function onMove(evt) { if (!this.dragging) return; this.currentY = evt.pageY || evt.touches[0].pageY; this.currentX = evt.pageX || evt.touches[0].pageX; // user is scrolling down to up if (this.currentY < this.startY) return; // 当前点与起始点形成的角度大于30度且小于150度时,下拉;其他情况不处理。 // 公式: (startY-currY)/(startX-currX)>1/√3~=0.58 // console.log("onMove evt", this.currentX, this.startX, this.currentY, this.startY); if (this.currentX !== this.startX) { var bi = Math.abs((this.startY - this.currentY) / (this.startX - this.currentX)); if (bi < 0.58) { // console.log('不能下拉呀'); return; } } if (this.isMoveEdge()) { //禁止整个页面下拉效果 evt.preventDefault(); evt.stopPropagation(); if (this.currentY - this.startY >= this.props.pullDownToRefreshThreshold) { if (this.state.currentState === 'deactivate') { this.setState({ currentState: 'activate' }); } } else { if (this.state.currentState !== 'deactivate') { this.setState({ currentState: 'deactivate' }); } } if (this.currentY - this.startY > this.props.maxPullDownDistance) return; this.container.style.overflow = 'visible'; this.setInfScrollStyle(this.currentY - this.startY); } } }, { key: "onEnd", value: function onEnd() { this.startY = 0; this.startX = 0; this.currentY = 0; this.currentX = 0; this.dragging = false; if (this.state.currentState === 'activate') { this.setState({ currentState: 'release' }); this.props.refreshFunction && this.props.refreshFunction(); } else { this.reset(); } } }, { key: "render", value: function render() { var _this$props = this.props, prefixCls = _this$props.prefixCls, className = _this$props.className, style = _this$props.style, indicator = _this$props.indicator, children = _this$props.children; var componentStyle = Object.assign({ height: 'auto', overflow: 'hidden', WebkitOverflowScrolling: 'touch' }, style); var outerDivStyle = { overflow: 'auto' }; return /*#__PURE__*/React.createElement("div", { style: outerDivStyle }, /*#__PURE__*/React.createElement("div", { className: className, ref: this.containerRef, style: componentStyle }, /*#__PURE__*/React.createElement("div", { className: "".concat(prefixCls, "-indicator") }, indicator[this.state.currentState] || INDICATOR[this.state.currentState]), children)); } }]); return PullToRefresh; }(React.PureComponent); export { PullToRefresh as default }; PullToRefresh.defaultProps = { pullDownToRefreshThreshold: 50, maxPullDownDistance: 100, disableBrowserPullToRefresh: true, style: {}, prefixCls: 'Yep-pull-to-refresh', indicator: INDICATOR, getScrollContainer: function getScrollContainer() { return undefined; } };