@tarojs/components
Version:
264 lines (260 loc) • 10.4 kB
JavaScript
import { r as registerInstance, c as createEvent, h, H as Host, g as getElement } from './index-5e431bb8.js';
import Taro from '@tarojs/taro';
import { c as classnames } from './index-b9522531.js';
const indexCss = ".rmc-pull-to-refresh-content{transform-origin:0 0}.rmc-pull-to-refresh-content-wrapper{min-height:100%}.rmc-pull-to-refresh-transition{transition:transform .3s}@keyframes rmc-pull-to-refresh-indicator{50%{opacity:.2}to{opacity:1}}.rmc-pull-to-refresh-indicator{text-align:center;height:30px;line-height:10px}.rmc-pull-to-refresh-indicator>div{background-color:gray;border-radius:100%;width:6px;height:6px;margin:3px;animation:.5s linear infinite both rmc-pull-to-refresh-indicator;display:inline-block}.rmc-pull-to-refresh-indicator>div:nth-child(0){animation-delay:-.1s!important}.rmc-pull-to-refresh-indicator>div:first-child{animation-delay:-.2s!important}.rmc-pull-to-refresh-indicator>div:nth-child(2){animation-delay:-.3s!important}.rmc-pull-to-refresh-down .rmc-pull-to-refresh-indicator{margin-top:-25px}";
function setTransform(nodeStyle, value) {
nodeStyle.transform = value;
nodeStyle.webkitTransform = value;
nodeStyle.MozTransform = value;
}
const isWebView = typeof navigator !== 'undefined' &&
/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent);
const INDICATOR = {
activate: 'release',
deactivate: 'pull',
release: 'loading',
finish: 'finish'
};
let supportsPassive = false;
try {
const opts = Object.defineProperty({}, 'passive', {
get() {
supportsPassive = true;
}
});
window.addEventListener('cancel', () => ({}), opts);
}
catch (e) { }
const willPreventDefault = supportsPassive ? { passive: false } : false;
const PullToRefresh = class {
constructor(hostRef) {
registerInstance(this, hostRef);
this.onRefresh = createEvent(this, "refresh", 7);
this._ScreenY = 0;
this._startScreenY = 0;
this._lastScreenY = 0;
this._isMounted = false;
this.triggerPullDownRefresh = (flag) => {
// 在初始化时、用代码 自动 触发 pullDownRefresh
// 添加this._isMounted的判断,否则组建一实例化,currSt就会是finish
if (!this.dragOnEdge && this._isMounted) {
if (flag) {
this._lastScreenY = this.distanceToRefresh + 1;
// change dom need after setState
this.currSt = 'release';
this.setContentStyle(this._lastScreenY);
}
else {
this.currSt = 'finish';
this.reset();
}
}
};
this.init = () => {
const ele = this.scrollContainer;
const child = this.el.querySelector('.rmc-pull-to-refresh-content');
this.el.appendChild = child === null || child === void 0 ? void 0 : child.appendChild.bind(child);
this.el.insertBefore = child === null || child === void 0 ? void 0 : child.insertBefore.bind(child);
this.el.replaceChild = child === null || child === void 0 ? void 0 : child.replaceChild.bind(child);
this.el.removeChild = child === null || child === void 0 ? void 0 : child.removeChild.bind(child);
this._to = {
touchstart: this.onTouchStart.bind(this, ele),
touchmove: this.onTouchMove.bind(this, ele),
touchend: this.onTouchEnd.bind(this, ele),
touchcancel: this.onTouchEnd.bind(this, ele)
};
Object.keys(this._to).forEach(key => {
ele.addEventListener(key, this._to[key], willPreventDefault);
});
};
this.destroy = () => {
// fix 频繁切换页面,可能会导致 this._to 为空造成报错
if (!this._to)
return;
const ele = this.scrollContainer;
Object.keys(this._to).forEach(key => {
ele.removeEventListener(key, this._to[key]);
});
};
this.onTouchStart = (_, e) => {
this._ScreenY = this._startScreenY = e.touches[0].screenY;
// 一开始 refreshing 为 true 时 this._lastScreenY 有值
this._lastScreenY = this._lastScreenY || 0;
};
this.isEdge = (ele) => {
const container = this.scrollContainer;
if (container && container === document.body) {
// In chrome61 `document.body.scrollTop` is invalid
const scrollNode = document.scrollingElement ? document.scrollingElement : document.body;
return scrollNode.scrollTop <= 0;
}
return ele.scrollTop <= 0;
};
this.damp = (dy) => {
if (Math.abs(this._lastScreenY) > this.damping) {
return 0;
}
const ratio = Math.abs(this._ScreenY - this._startScreenY) / window.screen.height;
dy *= (1 - ratio) * 0.6;
return dy;
};
this.onTouchMove = (ele, e) => {
// 使用 pageY 对比有问题
const _screenY = e.touches[0].screenY;
// 拖动方向不符合的不处理
if (this._startScreenY > _screenY) {
return;
}
if (this.isEdge(ele)) {
if (!this.dragOnEdge) {
// 当用户开始往上滑的时候isEdge还是false的话,会导致this._ScreenY不是想要的,只有当isEdge为true时,再上滑,才有意义
// 下面这行代码解决了上面这个问题
this._ScreenY = this._startScreenY = e.touches[0].screenY;
this.dragOnEdge = true;
}
if (e.cancelable) {
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();
const _diff = Math.round(_screenY - this._ScreenY);
this._ScreenY = _screenY;
this._lastScreenY += this.damp(_diff);
this.setContentStyle(this._lastScreenY);
if (Math.abs(this._lastScreenY) < this.distanceToRefresh) {
if (this.currSt !== 'deactivate') {
// console.log('back to the distance');
this.currSt = 'deactivate';
}
}
else {
if (this.currSt === 'deactivate') {
// console.log('reach to the distance');
this.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) {
this.onTouchEnd();
}
}
};
this.onTouchEnd = () => {
if (this.dragOnEdge) {
this.dragOnEdge = false;
}
if (this.currSt === 'activate') {
this.currSt = 'release';
this.onRefresh.emit(this);
this._lastScreenY = this.distanceToRefresh + 1;
this.setContentStyle(this._lastScreenY);
}
else if (this.currSt === 'release') {
this._lastScreenY = this.distanceToRefresh + 1;
this.setContentStyle(this._lastScreenY);
}
else {
this.reset();
}
};
this.reset = () => {
this._lastScreenY = 0;
this.setContentStyle(0);
};
this.setContentStyle = (ty) => {
// TODO: Why sometimes do not have `this.contentRef` ?
if (this.contentRef) {
// translate3d 不清理 会影响内部元素 定位
if (ty) {
setTransform(this.contentRef.style, `translate3d(0px,${ty}px,0)`);
}
else {
setTransform(this.contentRef.style, '');
}
}
};
this.prefixCls = 'rmc-pull-to-refresh';
this.distanceToRefresh = 50;
this.damping = 100;
this.indicator = INDICATOR;
this.currSt = 'deactivate';
this.dragOnEdge = false;
}
get scrollContainer() {
return this.el.parentElement ||
this.el.closest('.taro_page_stationed') ||
document.querySelector('.taro_page_stationed') ||
document.querySelector('.taro_page') ||
document.querySelector('.taro_router') ||
document.querySelector('.taro-tabbar__panel') ||
document.body;
}
statusChange() {
var _a, _b, _c, _d;
const pageEl = this.scrollContainer;
switch (this.currSt) {
case 'release':
(_b = (_a = pageEl === null || pageEl === void 0 ? void 0 : pageEl.__page) === null || _a === void 0 ? void 0 : _a.onPullDownRefresh) === null || _b === void 0 ? void 0 : _b.call(_a);
break;
case 'deactivate':
(_d = (_c = pageEl === null || pageEl === void 0 ? void 0 : pageEl.__page) === null || _c === void 0 ? void 0 : _c.onPullIntercept) === null || _d === void 0 ? void 0 : _d.call(_c);
}
}
disconnectedCallback() {
this.destroy();
}
componentDidLoad() {
this.init();
this._isMounted = true;
Taro.eventCenter.on('__taroStartPullDownRefresh', ({ successHandler, errorHandler }) => {
try {
this.triggerPullDownRefresh(true);
successHandler({
errMsg: 'startPullDownRefresh: ok'
});
}
catch (e) {
errorHandler({
errMsg: 'startPullDownRefresh: fail'
});
}
});
Taro.eventCenter.on('__taroStopPullDownRefresh', ({ successHandler, errorHandler }) => {
setTimeout(() => {
try {
this.triggerPullDownRefresh(false);
successHandler({
errMsg: 'stopPullDownRefresh: ok'
});
}
catch (e) {
errorHandler({
errMsg: 'stopPullDownRefresh: fail'
});
}
}, 0);
});
}
render() {
const renderRefresh = (cls) => {
const { currSt, dragOnEdge, prefixCls } = this;
const cla = classnames(cls, !dragOnEdge && `${prefixCls}-transition`);
const showIndicator = currSt === 'activate' || currSt === 'release';
return (h("div", { class: `${prefixCls}-content-wrapper` }, h("div", { class: cla, ref: el => {
this.contentRef = el;
} }, showIndicator && (h("div", { class: `${prefixCls}-indicator` }, h("div", null), h("div", null), h("div", null))), h("slot", null))));
};
if (this.scrollContainer) {
return renderRefresh(`${this.prefixCls}-content ${this.prefixCls}-down`);
}
return (h(Host, { class: classnames(this.prefixCls, `${this.prefixCls}-down`) }, renderRefresh(`${this.prefixCls}-content`)));
}
get el() { return getElement(this); }
static get watchers() { return {
"currSt": ["statusChange"]
}; }
};
PullToRefresh.style = indexCss;
export { PullToRefresh as taro_pull_to_refresh_core };