UNPKG

pull2

Version:

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

946 lines (921 loc) 42.9 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.pull2 = {})); })(this, (function (exports) { 'use strict'; /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; // 是否为 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; }()); exports.PullToRefresh = PullToRefresh; exports.ScrollToLoadMore = ScrollToLoadMore; })); //# sourceMappingURL=pull2.js.map