pull-down-refresh.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  2. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  3. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  4. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  5. return c > 3 && r && Object.defineProperty(target, key, r), r;
  6. };
  7. /* eslint-disable dot-notation */
  8. /* eslint-disable prefer-destructuring */
  9. import { SuperComponent, wxComponent } from '../common/src/index';
  10. import config from '../common/config';
  11. import props from './props';
  12. const { prefix } = config;
  13. const name = `${prefix}-pull-down-refresh`;
  14. let PullDownRefresh = class PullDownRefresh extends SuperComponent {
  15. constructor() {
  16. super(...arguments);
  17. this.isScrollToTop = true;
  18. this.pixelRatio = 1; // 像素比(rpx与px在此设备上的比值)
  19. this.startPoint = null; // 下拉开始的起点,主要用于计算下拉高度
  20. this.isPulling = false; // 是否下拉中
  21. this.defaultBarHeight = 0; // 下拉效果的默认高度
  22. this.maxBarHeight = 276; // 最大下拉高度,单位 rpx
  23. // 触发刷新的下拉高度,单位rpx
  24. // 松开时下拉高度大于这个值即会触发刷新,触发刷新后松开,会恢复到这个高度并保持,直到刷新结束
  25. this.loadingBarHeight = 200;
  26. this.refreshTimeout = 3000; // 刷新超时时间,超过没有回调刷新成功,会自动结束刷新动画。单位 ms
  27. /** 开始刷新 - 刷新成功/失败 最小间隔时间setTimeout句柄 */
  28. this.minRefreshTimeFlag = 0;
  29. /** 刷新成功/失败 - 关闭刷新动画 最小间隔时间setTimeout句柄 */
  30. this.minRefreshStatusShowTimeFlag = 0;
  31. /** 开始刷新 - 刷新成功/失败 最大间隔时间setTimeout句柄 */
  32. this.maxRefreshAnimateTimeFlag = 0;
  33. /** 关闭动画耗时setTimeout句柄 */
  34. this.closingAnimateTimeFlag = 0;
  35. this.externalClasses = ['t--class', 't-class-loading', 't-class-tex', 't-class-indicator'];
  36. this.options = {
  37. multipleSlots: true,
  38. };
  39. this.properties = props;
  40. this.data = {
  41. classPrefix: name,
  42. barHeight: this.defaultBarHeight,
  43. refreshStatus: 0,
  44. refreshTypes: ['not-start', 'wait-start', 'refreshing', 'success', 'finishing'],
  45. rotate: 0, // 旋转角度,refreshStatus为0、1时根据下拉距离动态计算得出
  46. };
  47. }
  48. attached() {
  49. const systemInfo = wx.getSystemInfoSync();
  50. // 计算像素比
  51. this.screenWidth = systemInfo.screenWidth;
  52. this.pixelRatio = 750 / systemInfo.screenWidth;
  53. // 判断是否ios
  54. this.ios = !!(systemInfo.system.toLowerCase().search('ios') + 1);
  55. // 自定义拉下宽度
  56. const maxBarHeight = this.properties.maxBarHeight;
  57. if (maxBarHeight) {
  58. this.maxBarHeight = maxBarHeight;
  59. }
  60. const loadingBarHeight = this.properties.loadingBarHeight;
  61. if (loadingBarHeight) {
  62. this.loadingBarHeight = loadingBarHeight;
  63. }
  64. const refreshTimeout = this.properties.refreshTimeout;
  65. if (refreshTimeout) {
  66. this.refreshTimeout = refreshTimeout;
  67. }
  68. }
  69. detached() {
  70. this.cleanTimeFlag();
  71. }
  72. onPageScroll(e) {
  73. const { scrollTop } = e;
  74. this.isScrollToTop = scrollTop === 0;
  75. }
  76. /** 清理timeout */
  77. cleanTimeFlag() {
  78. clearTimeout(this.minRefreshTimeFlag);
  79. clearTimeout(this.minRefreshStatusShowTimeFlag);
  80. clearTimeout(this.maxRefreshAnimateTimeFlag);
  81. clearTimeout(this.closingAnimateTimeFlag);
  82. }
  83. onTouchStart(e) {
  84. // 如果页面没滚动到顶部,不做处理
  85. // 如果下拉效果没有结束,不做处理
  86. if (!this.isScrollToTop || this.isPulling)
  87. return;
  88. const { touches } = e;
  89. if (touches.length !== 1)
  90. return;
  91. const { pageX, pageY } = touches[0];
  92. this.startPoint = { pageX, pageY }; // 设置起点
  93. this.isPulling = true; // 进入下拉状态
  94. }
  95. onTouchMove(e) {
  96. // 如果页面没滚到顶部,不做处理
  97. // 如果没有起点,不做处理
  98. if (!this.isScrollToTop || !this.startPoint)
  99. return;
  100. const { touches } = e;
  101. if (touches.length !== 1)
  102. return;
  103. const { pageY } = touches[0];
  104. const offset = pageY - this.startPoint.pageY;
  105. const barHeight = this.toRpx(offset);
  106. if (barHeight > 0) {
  107. if (barHeight > this.maxBarHeight) {
  108. // 限高
  109. this.setRefreshBarHeight(this.maxBarHeight);
  110. this.startPoint.pageY = pageY - this.toPx(this.maxBarHeight); // 限高的同时修正起点,避免触摸点上移时无效果
  111. }
  112. else {
  113. this.setRefreshBarHeight(barHeight);
  114. }
  115. }
  116. }
  117. onTouchEnd(e) {
  118. // 如果没有起点,不做处理
  119. if (!this.startPoint)
  120. return;
  121. const { changedTouches } = e;
  122. if (changedTouches.length !== 1)
  123. return;
  124. const { pageY } = changedTouches[0];
  125. const barHeight = this.toRpx(pageY - this.startPoint.pageY);
  126. this.startPoint = null; // 清掉起点,之后将忽略touchMove、touchEnd事件
  127. // 松开时高度超过阈值则触发刷新
  128. if (barHeight > this.loadingBarHeight) {
  129. this.setData({
  130. barHeight: this.loadingBarHeight,
  131. rotate: 0,
  132. refreshStatus: 2,
  133. }); // 正在刷新
  134. const startTime = Date.now();
  135. const callback = () => {
  136. // 正在刷新效果至少持续1秒钟
  137. const remainTime = 1000 - (Date.now() - startTime);
  138. this.minRefreshTimeFlag = setTimeout(() => {
  139. // 清理自身timeout
  140. this.minRefreshTimeFlag = 0;
  141. // 如果还没超时
  142. if (this.maxRefreshAnimateTimeFlag) {
  143. // 清理超时setup
  144. clearTimeout(this.maxRefreshAnimateTimeFlag);
  145. this.maxRefreshAnimateTimeFlag = 0;
  146. // 执行成功状态展示
  147. this.setData({ refreshStatus: 3 }); // 刷新成功
  148. this.minRefreshStatusShowTimeFlag = setTimeout(() => {
  149. this.minRefreshStatusShowTimeFlag = 0;
  150. this.close();
  151. }, 1000); // 刷新成功展示持续一段时间后再结束
  152. }
  153. }, remainTime > 0 ? remainTime : 0);
  154. };
  155. this.triggerEvent('refresh', { callback });
  156. this.maxRefreshAnimateTimeFlag = setTimeout(() => {
  157. // 清理自身timeout
  158. this.maxRefreshAnimateTimeFlag = 0;
  159. if (this.data.refreshStatus === 2) {
  160. // 超时回调
  161. this.triggerEvent('timeout');
  162. this.close(); // 超时仍未被回调,则直接结束下拉
  163. }
  164. }, this.refreshTimeout);
  165. }
  166. else {
  167. this.close();
  168. }
  169. }
  170. toRpx(v) {
  171. return v * this.pixelRatio;
  172. }
  173. toPx(v) {
  174. return v / this.pixelRatio;
  175. }
  176. setRefreshBarHeight(barHeight) {
  177. const data = { barHeight };
  178. if (barHeight >= this.loadingBarHeight) {
  179. data.refreshStatus = 1;
  180. data.rotate = -720; // 大于正常高度后不再旋转
  181. }
  182. else {
  183. data.refreshStatus = 0;
  184. data.rotate = (barHeight / this.loadingBarHeight) * -720; // 小于正常高度时随下拉高度旋转720度
  185. }
  186. return new Promise((resolve) => {
  187. this.setData(data, () => resolve(barHeight));
  188. });
  189. }
  190. close() {
  191. this.setData({ barHeight: this.defaultBarHeight, refreshStatus: 4 }); // 结束下拉
  192. this.closingAnimateTimeFlag = setTimeout(() => {
  193. // 清理自身timeout
  194. this.closingAnimateTimeFlag = 0;
  195. if (this.minRefreshStatusShowTimeFlag) {
  196. clearTimeout(this.minRefreshStatusShowTimeFlag);
  197. this.minRefreshStatusShowTimeFlag = 0;
  198. }
  199. this.setData({ refreshStatus: 0 });
  200. this.isPulling = false; // 退出下拉状态
  201. }, 1000);
  202. }
  203. };
  204. PullDownRefresh = __decorate([
  205. wxComponent()
  206. ], PullDownRefresh);
  207. export default PullDownRefresh;
  208. //# sourceMappingURL=pull-down-refresh.js.map