pull-down.esm.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*!
  2. * better-scroll / pull-down
  3. * (c) 2016-2021 ustbhuangyi
  4. * Released under the MIT License.
  5. */
  6. // ssr support
  7. var inBrowser = typeof window !== 'undefined';
  8. var ua = inBrowser && navigator.userAgent.toLowerCase();
  9. !!(ua && /wechatdevtools/.test(ua));
  10. ua && ua.indexOf('android') > 0;
  11. /* istanbul ignore next */
  12. ((function () {
  13. if (typeof ua === 'string') {
  14. var regex = /os (\d\d?_\d(_\d)?)/;
  15. var matches = regex.exec(ua);
  16. if (!matches)
  17. return false;
  18. var parts = matches[1].split('_').map(function (item) {
  19. return parseInt(item, 10);
  20. });
  21. // ios version >= 13.4 issue 982
  22. return !!(parts[0] === 13 && parts[1] >= 4);
  23. }
  24. return false;
  25. }))();
  26. /* istanbul ignore next */
  27. var supportsPassive = false;
  28. /* istanbul ignore next */
  29. if (inBrowser) {
  30. var EventName = 'test-passive';
  31. try {
  32. var opts = {};
  33. Object.defineProperty(opts, 'passive', {
  34. get: function () {
  35. supportsPassive = true;
  36. },
  37. }); // https://github.com/facebook/flow/issues/285
  38. window.addEventListener(EventName, function () { }, opts);
  39. }
  40. catch (e) { }
  41. }
  42. var extend = function (target, source) {
  43. for (var key in source) {
  44. target[key] = source[key];
  45. }
  46. return target;
  47. };
  48. var elementStyle = (inBrowser &&
  49. document.createElement('div').style);
  50. var vendor = (function () {
  51. /* istanbul ignore if */
  52. if (!inBrowser) {
  53. return false;
  54. }
  55. var transformNames = [
  56. {
  57. key: 'standard',
  58. value: 'transform',
  59. },
  60. {
  61. key: 'webkit',
  62. value: 'webkitTransform',
  63. },
  64. {
  65. key: 'Moz',
  66. value: 'MozTransform',
  67. },
  68. {
  69. key: 'O',
  70. value: 'OTransform',
  71. },
  72. {
  73. key: 'ms',
  74. value: 'msTransform',
  75. },
  76. ];
  77. for (var _i = 0, transformNames_1 = transformNames; _i < transformNames_1.length; _i++) {
  78. var obj = transformNames_1[_i];
  79. if (elementStyle[obj.value] !== undefined) {
  80. return obj.key;
  81. }
  82. }
  83. /* istanbul ignore next */
  84. return false;
  85. })();
  86. /* istanbul ignore next */
  87. function prefixStyle(style) {
  88. if (vendor === false) {
  89. return style;
  90. }
  91. if (vendor === 'standard') {
  92. if (style === 'transitionEnd') {
  93. return 'transitionend';
  94. }
  95. return style;
  96. }
  97. return vendor + style.charAt(0).toUpperCase() + style.substr(1);
  98. }
  99. vendor && vendor !== 'standard' ? '-' + vendor.toLowerCase() + '-' : '';
  100. var transform = prefixStyle('transform');
  101. var transition = prefixStyle('transition');
  102. inBrowser && prefixStyle('perspective') in elementStyle;
  103. ({
  104. transform: transform,
  105. transition: transition,
  106. transitionTimingFunction: prefixStyle('transitionTimingFunction'),
  107. transitionDuration: prefixStyle('transitionDuration'),
  108. transitionDelay: prefixStyle('transitionDelay'),
  109. transformOrigin: prefixStyle('transformOrigin'),
  110. transitionEnd: prefixStyle('transitionEnd'),
  111. transitionProperty: prefixStyle('transitionProperty'),
  112. });
  113. var ease = {
  114. // easeOutQuint
  115. swipe: {
  116. style: 'cubic-bezier(0.23, 1, 0.32, 1)',
  117. fn: function (t) {
  118. return 1 + --t * t * t * t * t;
  119. }
  120. },
  121. // easeOutQuard
  122. swipeBounce: {
  123. style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
  124. fn: function (t) {
  125. return t * (2 - t);
  126. }
  127. },
  128. // easeOutQuart
  129. bounce: {
  130. style: 'cubic-bezier(0.165, 0.84, 0.44, 1)',
  131. fn: function (t) {
  132. return 1 - --t * t * t * t;
  133. }
  134. }
  135. };
  136. var sourcePrefix = 'plugins.pullDownRefresh';
  137. var propertiesMap = [
  138. {
  139. key: 'finishPullDown',
  140. name: 'finishPullDown'
  141. },
  142. {
  143. key: 'openPullDown',
  144. name: 'openPullDown'
  145. },
  146. {
  147. key: 'closePullDown',
  148. name: 'closePullDown'
  149. },
  150. {
  151. key: 'autoPullDownRefresh',
  152. name: 'autoPullDownRefresh'
  153. }
  154. ];
  155. var propertiesConfig = propertiesMap.map(function (item) {
  156. return {
  157. key: item.key,
  158. sourceKey: sourcePrefix + "." + item.name
  159. };
  160. });
  161. var PULLING_DOWN_EVENT = 'pullingDown';
  162. var ENTER_THRESHOLD_EVENT = 'enterThreshold';
  163. var LEAVE_THRESHOLD_EVENT = 'leaveThreshold';
  164. var PullDown = /** @class */ (function () {
  165. function PullDown(scroll) {
  166. this.scroll = scroll;
  167. this.pulling = 0 /* DEFAULT */;
  168. this.thresholdBoundary = 0 /* DEFAULT */;
  169. this.init();
  170. }
  171. PullDown.prototype.setPulling = function (status) {
  172. this.pulling = status;
  173. };
  174. PullDown.prototype.setThresholdBoundary = function (boundary) {
  175. this.thresholdBoundary = boundary;
  176. };
  177. PullDown.prototype.init = function () {
  178. this.handleBScroll();
  179. this.handleOptions(this.scroll.options.pullDownRefresh);
  180. this.handleHooks();
  181. this.watch();
  182. };
  183. PullDown.prototype.handleBScroll = function () {
  184. this.scroll.registerType([
  185. PULLING_DOWN_EVENT,
  186. ENTER_THRESHOLD_EVENT,
  187. LEAVE_THRESHOLD_EVENT,
  188. ]);
  189. this.scroll.proxy(propertiesConfig);
  190. };
  191. PullDown.prototype.handleOptions = function (userOptions) {
  192. if (userOptions === void 0) { userOptions = {}; }
  193. userOptions = (userOptions === true ? {} : userOptions);
  194. var defaultOptions = {
  195. threshold: 90,
  196. stop: 40,
  197. };
  198. this.options = extend(defaultOptions, userOptions);
  199. this.scroll.options.probeType = 3 /* Realtime */;
  200. };
  201. PullDown.prototype.handleHooks = function () {
  202. var _this = this;
  203. this.hooksFn = [];
  204. var scroller = this.scroll.scroller;
  205. var scrollBehaviorY = scroller.scrollBehaviorY;
  206. this.currentMinScrollY = this.cachedOriginanMinScrollY =
  207. scrollBehaviorY.minScrollPos;
  208. this.registerHooks(this.scroll.hooks, this.scroll.hooks.eventTypes.contentChanged, function () {
  209. _this.finishPullDown();
  210. });
  211. this.registerHooks(scrollBehaviorY.hooks, scrollBehaviorY.hooks.eventTypes.computeBoundary, function (boundary) {
  212. // content is smaller than wrapper
  213. if (boundary.maxScrollPos > 0) {
  214. // allow scrolling when content is not full of wrapper
  215. boundary.maxScrollPos = -1;
  216. }
  217. boundary.minScrollPos = _this.currentMinScrollY;
  218. });
  219. // integrate with mousewheel
  220. if (this.hasMouseWheelPlugin()) {
  221. this.registerHooks(this.scroll, this.scroll.eventTypes.alterOptions, function (mouseWheelOptions) {
  222. var SANE_DISCRETE_TIME = 300;
  223. var SANE_EASE_TIME = 350;
  224. mouseWheelOptions.discreteTime = SANE_DISCRETE_TIME;
  225. // easeTime > discreteTime ensure goInto checkPullDown function
  226. mouseWheelOptions.easeTime = SANE_EASE_TIME;
  227. });
  228. this.registerHooks(this.scroll, this.scroll.eventTypes.mousewheelEnd, function () {
  229. // mouseWheel need trigger checkPullDown manually
  230. scroller.hooks.trigger(scroller.hooks.eventTypes.end);
  231. });
  232. }
  233. };
  234. PullDown.prototype.registerHooks = function (hooks, name, handler) {
  235. hooks.on(name, handler, this);
  236. this.hooksFn.push([hooks, name, handler]);
  237. };
  238. PullDown.prototype.hasMouseWheelPlugin = function () {
  239. return !!this.scroll.eventTypes.alterOptions;
  240. };
  241. PullDown.prototype.watch = function () {
  242. var scroller = this.scroll.scroller;
  243. this.watching = true;
  244. this.registerHooks(scroller.hooks, scroller.hooks.eventTypes.end, this.checkPullDown);
  245. this.registerHooks(this.scroll, this.scroll.eventTypes.scrollStart, this.resetStateBeforeScrollStart);
  246. this.registerHooks(this.scroll, this.scroll.eventTypes.scroll, this.checkLocationOfThresholdBoundary);
  247. if (this.hasMouseWheelPlugin()) {
  248. this.registerHooks(this.scroll, this.scroll.eventTypes.mousewheelStart, this.resetStateBeforeScrollStart);
  249. }
  250. };
  251. PullDown.prototype.resetStateBeforeScrollStart = function () {
  252. // current fetching pulldownRefresh has ended
  253. if (!this.isFetchingStatus()) {
  254. this.setPulling(1 /* MOVING */);
  255. this.setThresholdBoundary(0 /* DEFAULT */);
  256. }
  257. };
  258. PullDown.prototype.checkLocationOfThresholdBoundary = function () {
  259. // pulldownRefresh is in the phase of Moving
  260. if (this.pulling === 1 /* MOVING */) {
  261. var scroll_1 = this.scroll;
  262. // enter threshold boundary
  263. var enteredThresholdBoundary = this.thresholdBoundary !== 1 /* INSIDE */ &&
  264. this.locateInsideThresholdBoundary();
  265. // leave threshold boundary
  266. var leftThresholdBoundary = this.thresholdBoundary !== 2 /* OUTSIDE */ &&
  267. !this.locateInsideThresholdBoundary();
  268. if (enteredThresholdBoundary) {
  269. this.setThresholdBoundary(1 /* INSIDE */);
  270. scroll_1.trigger(ENTER_THRESHOLD_EVENT);
  271. }
  272. if (leftThresholdBoundary) {
  273. this.setThresholdBoundary(2 /* OUTSIDE */);
  274. scroll_1.trigger(LEAVE_THRESHOLD_EVENT);
  275. }
  276. }
  277. };
  278. PullDown.prototype.locateInsideThresholdBoundary = function () {
  279. return this.scroll.y <= this.options.threshold;
  280. };
  281. PullDown.prototype.unwatch = function () {
  282. var scroll = this.scroll;
  283. var scroller = scroll.scroller;
  284. this.watching = false;
  285. scroller.hooks.off(scroller.hooks.eventTypes.end, this.checkPullDown);
  286. scroll.off(scroll.eventTypes.scrollStart, this.resetStateBeforeScrollStart);
  287. scroll.off(scroll.eventTypes.scroll, this.checkLocationOfThresholdBoundary);
  288. if (this.hasMouseWheelPlugin()) {
  289. scroll.off(scroll.eventTypes.mousewheelStart, this.resetStateBeforeScrollStart);
  290. }
  291. };
  292. PullDown.prototype.checkPullDown = function () {
  293. var _a = this.options, threshold = _a.threshold, stop = _a.stop;
  294. // check if a real pull down action
  295. if (this.scroll.y < threshold) {
  296. return false;
  297. }
  298. if (this.pulling === 1 /* MOVING */) {
  299. this.modifyBehaviorYBoundary(stop);
  300. this.setPulling(2 /* FETCHING */);
  301. this.scroll.trigger(PULLING_DOWN_EVENT);
  302. }
  303. this.scroll.scrollTo(this.scroll.x, stop, this.scroll.options.bounceTime, ease.bounce);
  304. return this.isFetchingStatus();
  305. };
  306. PullDown.prototype.isFetchingStatus = function () {
  307. return this.pulling === 2 /* FETCHING */;
  308. };
  309. PullDown.prototype.modifyBehaviorYBoundary = function (stopDistance) {
  310. var scrollBehaviorY = this.scroll.scroller.scrollBehaviorY;
  311. // manually modify minScrollPos for a hang animation
  312. // to prevent from resetPosition
  313. this.cachedOriginanMinScrollY = scrollBehaviorY.minScrollPos;
  314. this.currentMinScrollY = stopDistance;
  315. scrollBehaviorY.computeBoundary();
  316. };
  317. PullDown.prototype.finishPullDown = function () {
  318. if (this.isFetchingStatus()) {
  319. var scrollBehaviorY = this.scroll.scroller.scrollBehaviorY;
  320. // restore minScrollY since the hang animation has ended
  321. this.currentMinScrollY = this.cachedOriginanMinScrollY;
  322. scrollBehaviorY.computeBoundary();
  323. this.setPulling(0 /* DEFAULT */);
  324. this.scroll.resetPosition(this.scroll.options.bounceTime, ease.bounce);
  325. }
  326. };
  327. // allow 'true' type is compat for beta version implements
  328. PullDown.prototype.openPullDown = function (config) {
  329. if (config === void 0) { config = {}; }
  330. this.handleOptions(config);
  331. if (!this.watching) {
  332. this.watch();
  333. }
  334. };
  335. PullDown.prototype.closePullDown = function () {
  336. this.unwatch();
  337. };
  338. PullDown.prototype.autoPullDownRefresh = function () {
  339. var _a = this.options, threshold = _a.threshold, stop = _a.stop;
  340. if (this.isFetchingStatus() || !this.watching) {
  341. return;
  342. }
  343. this.modifyBehaviorYBoundary(stop);
  344. this.scroll.trigger(this.scroll.eventTypes.scrollStart);
  345. this.scroll.scrollTo(this.scroll.x, threshold);
  346. this.setPulling(2 /* FETCHING */);
  347. this.scroll.trigger(PULLING_DOWN_EVENT);
  348. this.scroll.scrollTo(this.scroll.x, stop, this.scroll.options.bounceTime, ease.bounce);
  349. };
  350. PullDown.pluginName = 'pullDownRefresh';
  351. return PullDown;
  352. }());
  353. export default PullDown;