UNPKG

pull2

Version:

提供了下拉刷新、滚动底部加载组件。原生 js 开发,不依赖任何框架,也可以集成到任何框架。

853 lines (838 loc) 34.3 kB
import { __extends, __assign, __awaiter, __generator } from 'tslib'; // 是否为 window 对象 var isWindow = function (obj) { return obj !== null && obj !== undefined && obj === (obj === null || obj === void 0 ? void 0 : obj.window); }; // 是否支持Touch事件 var isSupportTouch = typeof window === 'object' && window && 'ontouchstart' in window; // 事件 var Events = { start: isSupportTouch ? 'touchstart' : 'mousedown', move: isSupportTouch ? 'touchmove' : 'mousemove', end: isSupportTouch ? 'touchend' : 'mouseup', cancel: 'touchcancel' }; // 获取滚动条距离顶部长度 function getScrollTop(el) { var top = 0; if (el === document.body || el === document.documentElement) { top = Math.max(document.body.scrollTop, document.documentElement.scrollTop); } else { top = 'scrollTop' in el ? el.scrollTop : el.scrollY; } return top; } // 获取事件触发客户端坐标 function getClient(e) { var x = 0, y = 0; if (typeof e.clientX === 'number' && typeof e.clientY === 'number') { x = e.clientX; y = e.clientY; } else if (e.touches && e.touches[0]) { x = e.touches[0].clientX; y = e.touches[0].clientY; } else if (e.changedTouches && e.changedTouches[0]) { x = e.changedTouches[0].clientX; y = e.changedTouches[0].clientY; } return { clientX: x, clientY: y }; } function formatPx(num) { return typeof num === 'number' ? "".concat(num, "px") : num; } function hasOwnProperty(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } // 重绘 function reflow(el) { return el === null || el === void 0 ? void 0 : el.scrollTop; } // 获取可视高度 function getClientHeight(el) { if (typeof window === 'undefined') { return 0; } if (isWindow(el)) { return document.documentElement.clientHeight; } return el.clientHeight; } // 获取滚动高度 function getScrollHeight(el) { if (el === void 0) { el = window; } if (typeof window === 'undefined') { return 0; } if (isWindow(el)) { return document.documentElement.scrollHeight; } return el.scrollHeight; } // 节流 function throttle(fn, wait) { if (wait === void 0) { wait = 300; } // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-this-alias var context = this; var lastCallTime = Date.now(); var hasTimer = false; var cacheArgs = []; return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } cacheArgs = args; if (hasTimer) return; var now = Date.now(); var diffTime = now - lastCallTime; if (diffTime >= wait) { lastCallTime = now; fn.call(context, cacheArgs); } else { hasTimer = true; setTimeout(function () { hasTimer = false; lastCallTime = Date.now(); fn.call(context, cacheArgs); }, wait - diffTime); } }; } function processClass(className) { var cls = []; if (Array.isArray(className)) { cls = className; } else { cls = className && typeof className === 'string' ? [className] : []; } return cls; } var View = /** @class */ (function () { function View(element) { this.el = element ? element : document.createElement('div'); this.handler = {}; this.isUnmounted = false; // 标识卸载 this.transitionTimer = null; // 过度样式定时器 } View.prototype.on = function (type, listener, options) { if (this.isUnmounted) return; if (!this.handler[type]) { this.handler[type] = []; } this.handler[type].push(listener); this.el.addEventListener(type, listener, options); }; View.prototype.off = function (type, listener, options) { if (this.isUnmounted) return; this.el.removeEventListener(type, listener, options); }; View.prototype.setAttrs = function (obj) { if (this.isUnmounted) return; if (obj && typeof obj === 'object') { for (var prop in obj) { if (hasOwnProperty(obj, prop)) { this.el.setAttribute(prop, obj[prop]); } } } }; View.prototype.setStyle = function (obj) { if (this.isUnmounted) return; if (obj && typeof obj === 'object') { for (var prop in obj) { if (hasOwnProperty(obj, prop)) { // @ts-ignore this.el.style[prop] = obj[prop]; } } } }; View.prototype.updateTransition = function (enabled, propName) { if (enabled === void 0) { enabled = false; } if (propName === void 0) { propName = 'all'; } var transValue = enabled ? "".concat(propName, " .3s") : ''; this.setStyle({ transition: transValue }); }; View.prototype.html = function (htmlStr) { if (this.isUnmounted) return; this.el.innerHTML = htmlStr; }; View.prototype.getHeight = function () { var _a; return ((_a = this.el) === null || _a === void 0 ? void 0 : _a.clientHeight) || 0; }; View.prototype.setHeight = function (num) { this.setStyle({ height: formatPx(num) }); }; View.prototype.setTransitionHeight = function (num) { var _this = this; if (this.isUnmounted) return; clearTimeout(this.transitionTimer); this.updateTransition(true, 'height'); reflow(this.el); this.setHeight(num); this.transitionTimer = setTimeout(function () { _this.updateTransition(false); }, 300); }; View.prototype.addClass = function (className) { if (this.isUnmounted) return; var cls = processClass(className); if (cls.length <= 0) { return; } var prevClasses = this.el.getAttribute('class'); var arrPrevClasses = !prevClasses ? [] : prevClasses.split(' '); var arrNextClasses = arrPrevClasses .filter(function (itemCls) { return cls.indexOf(itemCls) === -1; }) .concat(cls); this.setAttrs({ class: arrNextClasses.join(' ') }); }; View.prototype.removeClass = function (className) { if (this.isUnmounted) return; var cls = processClass(className); if (cls.length <= 0) { return; } var prevClasses = this.el.getAttribute('class'); var arrPrevClasses = !prevClasses ? [] : prevClasses.split(' '); var arrNextClasses = arrPrevClasses.filter(function (itemCls) { return cls.indexOf(itemCls) === -1; }); this.setAttrs({ class: arrNextClasses.join(' ') }); }; View.prototype.show = function () { this.setStyle({ display: 'block' }); }; View.prototype.hide = function () { this.setStyle({ display: 'none' }); }; View.prototype.destroy = function () { var _a; if (this.isUnmounted) return; for (var type in this.handler) { if (this.handler[type].length > 0) { for (var i = 0; i < this.handler[type].length; i++) { this.off(type, this.handler[type][i]); } this.handler[type].length = 0; } delete this.handler[type]; } (_a = this.el.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.el); this.isUnmounted = true; }; return View; }()); function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var css_248z$1 = "@-webkit-keyframes pull2-animate-spin {\n 0% {\n -webkit-transform: rotate(0);\n transform: rotate(0);\n }\n 100% {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n@keyframes pull2-animate-spin {\n 0% {\n -webkit-transform: rotate(0);\n transform: rotate(0);\n }\n 100% {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n.pull2-icon {\n display: inline-block;\n box-sizing: content-box;\n vertical-align: middle;\n}\n.pull2-icon-spin {\n -webkit-animation: pull2-animate-spin 1s linear infinite;\n animation: pull2-animate-spin 1s linear infinite;\n}\n.pull2-icon-circle {\n position: relative;\n width: 10px;\n height: 10px;\n border: 2px solid #009def;\n border-right-color: transparent;\n border-radius: 50%;\n}\n.pull2-icon-x {\n position: relative;\n width: 14px;\n height: 14px;\n}\n.pull2-icon-x::before,\n.pull2-icon-x::after {\n position: absolute;\n top: 0;\n left: 6px;\n width: 2px;\n height: 14px;\n background: #ee693b;\n -webkit-transform: rotate(45deg);\n transform: rotate(45deg);\n content: '';\n}\n.pull2-icon-x::after {\n -webkit-transform: rotate(135deg);\n transform: rotate(135deg);\n}\n.pull2-icon-check {\n display: inline-block;\n width: 12px;\n height: 6px;\n margin-top: -3px;\n border: 2px solid #13b418;\n border-width: 0 0 2px 2px;\n -webkit-transform: rotate(-45deg);\n transform: rotate(-45deg);\n}\n.pull2-to-refresh {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 40px;\n color: #777;\n font-size: 14px;\n}\n.pull2-to-refresh .pull2-icon {\n margin-right: 5px;\n}\n"; styleInject(css_248z$1); var _a$1, _b$1; // 内部状态 var State$1; (function (State) { State["Default"] = "default"; State["Drop"] = "drop"; State["Loading"] = "loading"; State["Success"] = "success"; State["Failed"] = "failed"; })(State$1 || (State$1 = {})); // 默认dom var defaultDom$1 = (_a$1 = {}, _a$1[State$1.Default] = '<span class="pull2-icon pull2-icon-circle"></span><%=text%>', _a$1[State$1.Drop] = '<span class="pull2-icon pull2-icon-circle"></span><%=text%>', _a$1[State$1.Loading] = '<span class="pull2-icon pull2-icon-circle pull2-icon-spin"></span><%=text%>', _a$1[State$1.Success] = '<span class="pull2-icon pull2-icon-check"></span><%=text%>', _a$1[State$1.Failed] = '<span class="pull2-icon pull2-icon-x"></span><%=text%>', _a$1); // 默认文本 var defaultText$1 = (_b$1 = {}, _b$1[State$1.Default] = '下拉刷新', _b$1[State$1.Drop] = '释放刷新', _b$1[State$1.Loading] = '刷新中...', _b$1[State$1.Success] = '刷新成功', _b$1[State$1.Failed] = '刷新失败', _b$1); var prefixCls$1 = 'pull2-to-refresh'; var RefreshView = /** @class */ (function (_super) { __extends(RefreshView, _super); function RefreshView(options) { var _this = _super.call(this) || this; _this.tplMarkText = '<%=text%>'; _this.state = State$1.Default; _this.options = __assign(__assign({ scrollView: document.documentElement }, options), { text: __assign(__assign({}, defaultText$1), options === null || options === void 0 ? void 0 : options.text), dom: __assign(__assign({}, defaultDom$1), options === null || options === void 0 ? void 0 : options.dom) }); _this.addClass([prefixCls$1, "".concat(prefixCls$1, "-").concat(_this.state)]); _this.setStyle({ height: '0px', overflow: 'hidden' }); _this.html(_this.getHtml(_this.state)); _this.render(); return _this; } RefreshView.prototype.__getWrapper = function (wrapper) { return isWindow(wrapper) || wrapper === document.documentElement ? document.body : wrapper; }; RefreshView.prototype.render = function () { var scrollView = this.options.scrollView; var wrapper = this.__getWrapper(scrollView); if (wrapper.firstChild) { wrapper.insertBefore(this.el, wrapper.firstChild); } else { wrapper.append(this.el); } }; RefreshView.prototype.updateOptions = function (options) { var changedWrapper = false; if (options.scrollView && options.scrollView !== this.options.scrollView) { changedWrapper = true; this.__getWrapper(this.options.scrollView).removeChild(this.el); } this.options = __assign(__assign(__assign({}, this.options), options), { text: __assign(__assign({}, this.options.text), options === null || options === void 0 ? void 0 : options.text), dom: __assign(__assign({}, this.options.dom), options === null || options === void 0 ? void 0 : options.dom) }); this.setState(this.state, true); if (changedWrapper) { this.render(); } }; RefreshView.prototype.getHtml = function (state) { var _a = this.options, dom = _a.dom, text = _a.text; return dom[state] ? dom[state].replace(this.tplMarkText, text[state]) : ''; }; RefreshView.prototype.setState = function (state, force) { if (force === void 0) { force = false; } if (this.state === state && !force) { return; } if (!hasOwnProperty(this.options.dom, state)) { throw 'RefreshView 不支持 ' + state + ' 状态'; } if (this.state !== state) { this.removeClass("".concat(prefixCls$1, "-").concat(this.state)); this.state = state; this.addClass("".concat(prefixCls$1, "-").concat(this.state)); } var htmlStr = this.getHtml(state); this.html(htmlStr); }; return RefreshView; }(View)); var TransitionDurantion = 300; // 动画过渡持续时间 var PullToRefresh = /** @class */ (function () { function PullToRefresh(options) { this.options = __assign({ height: 40, distance: 60, unmovableStayTime: 3000, completionStayTime: 500, scrollView: document.documentElement, isPullDown: function (diffY) { return diffY >= 0; } }, options); // 如没有设置 onRefresh ,不做任何处理 if (!this.options.onRefresh) { throw 'PullToRefresh 需要设置 onRefresh 回调方法'; } this.touchesStart = { x: 0, y: 0 }; // 开始坐标 this.diffY = 0; // 滑动距离 this.isTouch = false; // 标识触摸开始 this.isMove = false; // 标识触摸滑动 this.isLock = false; // 标识锁定 this.isUnmouted = false; // 标识卸载 this.calledLock = false; // 标识是否调用过lock方法 this.lockTimer = null; // 锁定定时器 this.completionStayTimer = null; // 停留定时器 this.__timerFixSlideOutScreen = null; // 定时器,修复滑出屏幕导致下拉刷新显示错误问题 this.handler = { start: this.fnTouchstart.bind(this), move: this.fnTouchmove.bind(this), end: this.fnTouchend.bind(this) }; this.init(); } PullToRefresh.prototype.init = function () { var _a = this.options, dom = _a.dom, text = _a.text, scrollView = _a.scrollView; this.view = new RefreshView({ dom: dom, text: text, scrollView: scrollView }); this.bindEvent(); }; // 绑定事件 PullToRefresh.prototype.bindEvent = function () { if (this.isUnmouted) return; var scrollView = this.options.scrollView; scrollView.addEventListener(Events.start, this.handler.start, { passive: false }); }; // 解绑事件 PullToRefresh.prototype.unbindEvent = function () { if (this.isUnmouted) return; var scrollView = this.options.scrollView; scrollView.removeEventListener(Events.start, this.handler.start); this.unbindDocumentEvent(); }; PullToRefresh.prototype.bindDocumentEvent = function () { document.addEventListener(Events.move, this.handler.move, { passive: false }); document.addEventListener(Events.end, this.handler.end, { passive: false }); document.addEventListener(Events.cancel, this.handler.end, { passive: false }); }; PullToRefresh.prototype.unbindDocumentEvent = function () { document.removeEventListener(Events.move, this.handler.move); document.removeEventListener(Events.end, this.handler.end); document.removeEventListener(Events.cancel, this.handler.end); }; // 开始触摸 PullToRefresh.prototype.fnTouchstart = function (e) { if (this.view.state !== State$1.Default || this.isLock) { return; } var scrollTop = getScrollTop(this.options.scrollView); // 滚动区域需置顶 if (scrollTop > 0) { return; } this.bindDocumentEvent(); this.isTouch = true; this.isMove = false; this.diffY = 0; this.view.updateTransition(false); var _a = getClient(e), clientX = _a.clientX, clientY = _a.clientY; this.touchesStart.x = clientX; this.touchesStart.y = clientY; }; // 触摸移动 PullToRefresh.prototype.fnTouchmove = function (e) { var _this = this; if (!this.isTouch) { return; } var _a = getClient(e), clientX = _a.clientX, clientY = _a.clientY; var diffY = clientY - this.touchesStart.y; if (!this.isMove) { var diffX = clientX - this.touchesStart.x; // 可能没有移动但是触发move事件 if (diffX === 0 && diffY === 0) { e.preventDefault(); return; } // 横向移动或往上滑动,不触发下拉刷新 if (!this.options.isPullDown(diffY)) { this.isTouch = false; return; } this.isMove = true; } e.preventDefault(); var _b = this.options, unmovableStayTime = _b.unmovableStayTime, distance = _b.distance; this.diffY = diffY; // 触摸停留2s后,执行touchend事件 clearTimeout(this.__timerFixSlideOutScreen); this.__timerFixSlideOutScreen = setTimeout(function () { _this.fnTouchend(); }, unmovableStayTime); // 下拉dom的偏移高度 var offsetY = 0; // 下拉 if (this.diffY <= distance) { offsetY = this.diffY; this.view.setState(State$1.Default); // 指定距离 < 下拉距离 < 指定距离*2 } else if (this.diffY > distance && this.diffY <= distance * 2) { offsetY = distance + (this.diffY - distance) * 0.5; this.view.setState(State$1.Drop); // 下拉距离 > 指定距离*2 } else { offsetY = distance + distance * 0.5 + (this.diffY - distance * 2) * 0.2; } this.view.setHeight(Math.max(offsetY, 0)); }; // 触摸结束 PullToRefresh.prototype.fnTouchend = function () { return __awaiter(this, void 0, void 0, function () { var _a, distance, completionStayTime, interval; var _this = this; return __generator(this, function (_b) { switch (_b.label) { case 0: clearTimeout(this.__timerFixSlideOutScreen); this.unbindDocumentEvent(); if (!this.isTouch || !this.isMove) { this.isTouch = false; this.isMove = false; return [2 /*return*/]; } _a = this.options, distance = _a.distance, completionStayTime = _a.completionStayTime; this.isTouch = false; this.isMove = false; this.internalLock(); interval = TransitionDurantion; if (!(this.diffY > distance)) return [3 /*break*/, 2]; return [4 /*yield*/, this.triggerRefresh()]; case 1: _b.sent(); interval += completionStayTime; return [3 /*break*/, 3]; case 2: this.view.setTransitionHeight(0); _b.label = 3; case 3: this.lockTimer = setTimeout(function () { _this.internalUnlock(); }, interval); return [2 /*return*/]; } }); }); }; // 重置 PullToRefresh.prototype.resetView = function () { var _this = this; this.completionStayTimer = setTimeout(function () { _this.view.setTransitionHeight(0); _this.completionStayTimer = setTimeout(function () { _this.view.setState(State$1.Default); }, 300); }, this.options.completionStayTime); }; // 触发下拉刷新 // 锁定后也支持外部手动触发 PullToRefresh.prototype.triggerRefresh = function () { var _this = this; // fix: 如果停留时,手动触发刷新,可能产生异常 if (this.isUnmouted || this.view.state === State$1.Loading) return; clearTimeout(this.completionStayTimer); this.view.setState(State$1.Loading); this.view.setTransitionHeight(this.options.height); return this.options .onRefresh() .then(function () { _this.view.setState(State$1.Success); }) .catch(function () { _this.view.setState(State$1.Failed); }) .finally(function () { _this.resetView(); }); }; // 内部锁定,锁定后将不再触发下拉刷新 PullToRefresh.prototype.internalLock = function () { clearTimeout(this.lockTimer); this.isLock = true; }; // 内部解除锁定 PullToRefresh.prototype.internalUnlock = function () { clearTimeout(this.lockTimer); if (!this.calledLock) { this.isLock = false; } }; // 暴露给外部的锁定方法 PullToRefresh.prototype.lock = function () { this.calledLock = true; this.internalLock(); }; // 暴露给外部的解除锁定方法 PullToRefresh.prototype.unlock = function () { this.calledLock = false; this.internalUnlock(); }; // 更新配置 PullToRefresh.prototype.updateOptions = function (options) { var changedScrollView = false; if ((options === null || options === void 0 ? void 0 : options.scrollView) && options.scrollView !== this.options.scrollView) { changedScrollView = true; this.unbindEvent(); } this.options = __assign(__assign({}, this.options), options); var _a = this.options, text = _a.text, dom = _a.dom, scrollView = _a.scrollView; this.view.updateOptions({ text: text, dom: dom, scrollView: scrollView }); if (changedScrollView) { this.bindEvent(); } }; // 销毁 PullToRefresh.prototype.destroy = function () { if (this.isUnmouted) return; this.internalLock(); this.unbindEvent(); this.view.destroy(); this.isUnmouted = true; }; // 恢复 PullToRefresh.prototype.resume = function () { if (!this.isUnmouted) return; this.isUnmouted = false; this.init(); this.internalUnlock(); }; return PullToRefresh; }()); var css_248z = ".pull2-load-more {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 44px;\n color: #777;\n font-size: 14px;\n}\n"; styleInject(css_248z); var _a, _b; // 内部状态 var State; (function (State) { State["Default"] = "default"; State["Loading"] = "loading"; State["Failed"] = "failed"; State["Done"] = "done"; })(State || (State = {})); // 默认dom var defaultDom = (_a = {}, _a[State.Default] = '<%=text%>', _a[State.Loading] = '<%=text%>', _a[State.Failed] = '<%=text%>', _a[State.Done] = '<%=text%>', _a); // 默认文本 var defaultText = (_b = {}, _b[State.Default] = '上拉或点击加载更多', _b[State.Loading] = '正在加载', _b[State.Failed] = '加载失败,点击重试', _b[State.Done] = '已全部加载', _b); var prefixCls = 'pull2-load-more'; var LoadMoreView = /** @class */ (function (_super) { __extends(LoadMoreView, _super); function LoadMoreView(options) { var _this = _super.call(this) || this; _this.tplMarkText = '<%=text%>'; _this.state = State.Default; _this.options = __assign(__assign({ scrollView: document.documentElement }, options), { text: __assign(__assign({}, defaultText), options === null || options === void 0 ? void 0 : options.text), dom: __assign(__assign({}, defaultDom), options === null || options === void 0 ? void 0 : options.dom) }); _this.addClass([prefixCls, "".concat(prefixCls, "-").concat(_this.state)]); _this.html(_this.getHtml(_this.state)); _this.render(); return _this; } LoadMoreView.prototype.__getWrapper = function (wrapper) { return isWindow(wrapper) || wrapper === document.documentElement ? document.body : wrapper; }; LoadMoreView.prototype.render = function () { var scrollView = this.options.scrollView; var wrapper = this.__getWrapper(scrollView); wrapper.appendChild(this.el); }; LoadMoreView.prototype.updateOptions = function (options) { var changedWrapper = false; if (options.scrollView && options.scrollView !== this.options.scrollView) { changedWrapper = true; this.__getWrapper(this.options.scrollView).removeChild(this.el); } this.options = __assign(__assign(__assign({}, this.options), options), { text: __assign(__assign({}, this.options.text), options === null || options === void 0 ? void 0 : options.text), dom: __assign(__assign({}, this.options.dom), options === null || options === void 0 ? void 0 : options.dom) }); this.setState(this.state, true); if (changedWrapper) { this.render(); } }; LoadMoreView.prototype.getHtml = function (state) { var _a = this.options, dom = _a.dom, text = _a.text; return dom[state] ? dom[state].replace(this.tplMarkText, text[state]) : ''; }; LoadMoreView.prototype.setState = function (state, force) { if (force === void 0) { force = false; } if (this.state === state && !force) { return; } if (!hasOwnProperty(this.options.dom, state)) { throw 'RefreshView 不支持 ' + state + ' 状态'; } if (this.state !== state) { this.removeClass("".concat(prefixCls, "-").concat(this.state)); this.state = state; this.addClass("".concat(prefixCls, "-").concat(this.state)); } var htmlStr = this.getHtml(state); this.html(htmlStr); }; return LoadMoreView; }(View)); var ScrollToLoadMore = /** @class */ (function () { function ScrollToLoadMore(options) { this.options = __assign({ threshold: 100, scrollView: document.documentElement, throttleWaitTime: 50, isNoMore: function () { return false; }, autoCheckOnContentUpdate: true }, options); // 如没有设置 onScrollLower ,不做任何处理 if (!this.options.onScrollLower) { throw 'ScrollToLoadMore 需要设置 onScrollLower 回调方法'; } this.isUnmouted = false; this.isLock = false; // 标识锁定 this.calledLock = false; // 标识外部调用lock方法 this.handler = { click: this.clickView.bind(this), scroll: throttle.call(this, this.scroll, this.options.throttleWaitTime > 0 ? this.options.throttleWaitTime : 0) }; this.init(); } ScrollToLoadMore.prototype.init = function () { var _a = this.options, text = _a.text, dom = _a.dom, scrollView = _a.scrollView; this.view = new LoadMoreView({ text: text, dom: dom, scrollView: scrollView }); this.bindEvent(); }; // 点击 ScrollToLoadMore.prototype.clickView = function () { if (this.isLock) return; if (this.view.state === State.Default || this.view.state === State.Failed) { this.triggerLoad(); } }; // 滚动 ScrollToLoadMore.prototype.scroll = function () { if (this.isLock || this.isUnmouted || this.view.state !== State.Default) return; this.checkLoad(); }; // 手动检测是否满足加载下一页条件,一般在页面刷新后调用 ScrollToLoadMore.prototype.checkLoad = function () { var _a = this.options, scrollView = _a.scrollView, threshold = _a.threshold; var height = getClientHeight(scrollView); // 容器高度 var scrollHeight = getScrollHeight(scrollView); // 内容高度 var scrollTop = getScrollTop(scrollView); if (height === 0 && scrollHeight === 0) { return; } if (scrollHeight - (threshold > 0 ? threshold : 0) <= height + scrollTop) { this.triggerLoad(); } }; ScrollToLoadMore.prototype.bindEvent = function () { var scrollView = this.options.scrollView; this.view.on('click', this.handler.click); var scrollWrapper = scrollView; if (scrollView === document.documentElement) { scrollWrapper = window; } scrollWrapper.addEventListener('scroll', this.handler.scroll); }; ScrollToLoadMore.prototype.unbindEvent = function () { var scrollView = this.options.scrollView; this.view.off('click', this.handler.click); var scrollWrapper = scrollView; if (scrollView === document.documentElement) { scrollWrapper = window; } scrollWrapper.removeEventListener('scroll', this.handler.scroll); }; ScrollToLoadMore.prototype.triggerLoad = function () { var _this = this; // 避免手动调用重复触发 if (this.isUnmouted || this.view.state === State.Loading) return; this.internalLock(); this.view.setState(State.Loading); var _a = this.options, onScrollLower = _a.onScrollLower, isNoMore = _a.isNoMore, autoCheckOnContentUpdate = _a.autoCheckOnContentUpdate; return onScrollLower() .then(function (res) { _this.internalUnlock(); if (isNoMore(res)) { _this.view.setState(State.Done); } else { _this.view.setState(State.Default); // 触发更新内容高度,滚动容器高度。 // 可以由外部触发。比如外部下拉刷新或者内容增删改,需要重新更新内容高度。 if (autoCheckOnContentUpdate) { _this.checkLoad(); } } return res; }) .catch(function () { _this.view.setState(State.Failed); _this.internalUnlock(); }); }; // 重置状态 ScrollToLoadMore.prototype.reset = function () { this.view.setState(State.Default); }; ScrollToLoadMore.prototype.updateOptions = function (options) { var changedScrollView = false; if ((options === null || options === void 0 ? void 0 : options.scrollView) && options.scrollView !== this.options.scrollView) { changedScrollView = true; this.unbindEvent(); } if (typeof (options === null || options === void 0 ? void 0 : options.throttleWaitTime) === 'number' && options.throttleWaitTime !== this.options.throttleWaitTime) { this.handler.scroll = throttle.call(this, this.scroll, options.throttleWaitTime > 0 ? options.throttleWaitTime : 0); } this.options = __assign(__assign({}, this.options), options); var _a = this.options, text = _a.text, dom = _a.dom, scrollView = _a.scrollView; this.view.updateOptions({ text: text, dom: dom, scrollView: scrollView }); if (changedScrollView) { this.bindEvent(); } }; // 内部锁定,锁定后将不再触发滚动底部加载 ScrollToLoadMore.prototype.internalLock = function () { this.isLock = true; }; // 内部解除锁定 ScrollToLoadMore.prototype.internalUnlock = function () { if (!this.calledLock) { this.isLock = false; } }; // 暴露给外部的锁定方法 ScrollToLoadMore.prototype.lock = function () { this.calledLock = true; this.internalLock(); }; // 暴露给外部的解除锁定方法 ScrollToLoadMore.prototype.unlock = function () { this.calledLock = false; this.internalUnlock(); }; ScrollToLoadMore.prototype.destroy = function () { if (this.isUnmouted) return; this.internalLock(); this.unbindEvent(); this.view.destroy(); this.isUnmouted = true; }; // 恢复 ScrollToLoadMore.prototype.resume = function () { if (!this.isUnmouted) return; this.isUnmouted = false; this.init(); this.internalUnlock(); }; return ScrollToLoadMore; }()); export { PullToRefresh, ScrollToLoadMore };