@jdcfe/yep-react
Version:
一套移动端的React组件库
251 lines (220 loc) • 8.72 kB
JavaScript
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;
}
};