Advertisement
Guest User

Untitled

a guest
Sep 20th, 2019
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.17 KB | None | 0 0
  1. import React, { useRef, useEffect, useState } from 'react';
  2.  
  3. class PullRefresh {
  4. constructor(opt) {
  5. this.options = opt;
  6. this.startPoint = null;
  7. this.pending = false;
  8. const { $scroll } = this.options;
  9. $scroll.addEventListener('touchmove', this.touchmove.bind(this));
  10. $scroll.addEventListener('touchend', this.touchend.bind(this));
  11. }
  12. getScrollPosition() {
  13. return this.options.$scroll.getClientsRect[0];
  14. }
  15. getSlidePosition() {
  16. return this.options.$slide.getClientsRect[0];
  17. }
  18. getDistance() {
  19. let { paddingTop, paddingBottom, borderTopWidth, borderBottomWidth } = window.getComputedStyle(this.options.$scroll);
  20. paddingTop = +paddingTop.replace('px', '');
  21. paddingBottom = +paddingBottom.replace('px', '');
  22. borderTopWidth = +borderTopWidth.replace('px', '');
  23. borderBottomWidth = +borderBottomWidth.replace('px', '');
  24. return (
  25. this.options.$scroll.scrollTop +
  26. (this.options.$scroll.offsetHeight - paddingTop - paddingBottom - borderTopWidth - borderBottomWidth) -
  27. this.options.$slide.offsetHeight
  28. );
  29. }
  30. atBottom() {
  31. const atBottom = this.getDistance() >= 0;
  32. return atBottom;
  33. }
  34. touchmove(e) {
  35. if (this.pending) return;
  36. if (this.options.disable()) return;
  37. const { clientY, clientX } = e.changedTouches[0];
  38.  
  39. if (!this.startPoint) {
  40. if (this.atBottom()) {
  41. // 刚好在边界处,往下滑动,此时scroll和slide底部在同一处,但响应touchmove之后,scroll会滚动,导致渲染之后scroll和slide的底部之间存在距离
  42. // e.preventDefault()
  43. this.startPoint = { x: clientX, y: clientY };
  44. this.options.onMoveStart && this.options.onMoveStart();
  45. }
  46. return;
  47. }
  48.  
  49. if (clientY > this.startPoint.y) {
  50. // 下移滚动
  51. this.options.$slide.style.transform = `translate3d(${0}px,${0}px,${0}px)`;
  52. }
  53. if (clientY < this.startPoint.y) {
  54. // 上拉刷新
  55. // e.preventDefault()
  56. console.log('上拉刷新');
  57. let offsetY = clientY - this.startPoint.y;
  58. if (offsetY < -50) offsetY = -50;
  59. this.options.$slide.style.transition = 'none';
  60. this.options.$slide.style.transform = `translate3d(${0}px,${offsetY}px,${0}px)`;
  61. }
  62. }
  63.  
  64. touchend(e) {
  65. if (!this.startPoint) return;
  66. const { clientY } = e.changedTouches[0];
  67. this.options.$slide.style.transition = 'transform 300ms linear';
  68. this.options.$slide.style.transform = `translate3d(${0}px,${0}px,${0}px)`;
  69. this.options.onMoveEnd && this.options.onMoveEnd();
  70. if (clientY - this.startPoint.y < -50) {
  71. this.pending = true;
  72. this.options.onPull(() => {
  73. this.pending = false;
  74. });
  75. }
  76. this.startPoint = null;
  77. }
  78. }
  79.  
  80. export default function Group() {
  81. let unlock = () => {};
  82. return props => {
  83. const $scroll = useRef(null);
  84. const $slide = useRef(null);
  85. // const [loading, setLoading] = useState(false);
  86. const [isShowTip, setShowTip] = useState(false);
  87. const [scrollHeight, _setScrollHeight] = useState(getScrollHeight());
  88. const [instance, setInstance] = useState(null);
  89. // const cb = () => {};
  90. function getScrollHeight() {
  91. return window.innerHeight - (50 * window.innerWidth) / 375;
  92. }
  93. function setScrollHeight() {
  94. _setScrollHeight(getScrollHeight());
  95. }
  96. useEffect(() => {
  97. window.addEventListener('resize', setScrollHeight);
  98. return () => {
  99. window.removeEventListener('resize', setScrollHeight);
  100. };
  101. }, []);
  102. // function stopPropagation(e) {
  103. // e.stopPropagation();
  104. // }
  105. // useEffect(() => {
  106. // $scroll.current.addEventListener('touchstart', stopPropagation);
  107. // $scroll.current.addEventListener('touchmove', stopPropagation);
  108. // return () => {
  109. // $scroll.current.removeEventListener('touchstart', stopPropagation);
  110. // $scroll.current.removeEventListener('touchmove', stopPropagation);
  111. // };
  112. // }, [$scroll]);
  113. useEffect(() => {
  114. const options = {
  115. $scroll: $scroll.current,
  116. $slide: $slide.current,
  117. disable() {
  118. return props.disable || props.loadOver || props.loading;
  119. },
  120. onMoveStart() {
  121. setShowTip(true);
  122. },
  123. onMoveEnd() {
  124. setShowTip(false);
  125. },
  126. onPull(cb) {
  127. unlock = cb;
  128. props.onPull();
  129. },
  130. };
  131. if (instance) {
  132. Object.assign(instance.options, options);
  133. return;
  134. }
  135. setInstance(new PullRefresh(options));
  136. }, [$scroll.current, $slide.current, props.onPull, props.disable, props.loading, props.loadOver]);
  137. useEffect(() => {
  138. if (props.loading) {
  139. instance.options.$scroll.scrollTop -= instance.getDistance();
  140. } else {
  141. unlock();
  142. }
  143. }, [props.loading]);
  144. return (
  145. <div
  146. className="scroll"
  147. ref={$scroll}
  148. style={{ overflowX: 'hidden', overflowY: 'scroll', height: scrollHeight, WebkitOverflowScrolling: 'touch' }}>
  149. <div
  150. className="slide"
  151. ref={$slide}
  152. style={{
  153. display: 'inline-block',
  154. width: '100%',
  155. verticalAlign: 'middle',
  156. }}>
  157. {props.children}
  158. {isShowTip ? props.tipNode : null}
  159. {props.loading ? props.loadingNode : null}
  160. {props.loadOver ? props.loadOverNode : null}
  161. </div>
  162. </div>
  163. );
  164. };
  165. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement