Guest User

Untitled

a guest
Oct 16th, 2018
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.27 KB | None | 0 0
  1. /**
  2. * @File 检查元素是否在视口中
  3. * @Author: yabingzyb.zhang
  4. * @Date: 2018-10-16 15:45:13
  5. * @Last Modified by: yabingzyb.zhang
  6. * @Last Modified time: 2018-10-16 17:43:12
  7. */
  8. import React, { Component, PropTypes } from 'react';
  9. import { View, Dimensions } from 'react-native';
  10.  
  11. // 滑动方向
  12. const DIRECTS = {
  13. UP: 'UP',
  14. DOWN: 'DOWN'
  15. };
  16.  
  17. export default class extends Component {
  18. static propTypes = {
  19. // 检查元素出现的方向:0: 所有方向,1:从下向上,2:从上向下,3:垂直方向
  20. type: PropTypes.number,
  21. // 检测元素位置间隔
  22. delay: PropTypes.number,
  23. // 状态发生变化时的回调
  24. onChange: PropTypes.func.isRequired,
  25. // 是否停止监听
  26. disabled: PropTypes.bool
  27. };
  28.  
  29. static defaultProps = {
  30. type: 0,
  31. delay: 100,
  32. disabled: false,
  33. onChange: () => { }
  34. };
  35.  
  36. constructor(props) {
  37. super(props);
  38.  
  39. this.state = {
  40. rectTop: 0,
  41. rectBottom: 0,
  42. verticalDirect: ''
  43. };
  44.  
  45. this.viewPort = null;
  46. }
  47.  
  48. componentDidMount() {
  49. if (!this.props.disabled) {
  50. this.startWatching();
  51. }
  52. }
  53.  
  54. componentWillUnmount() {
  55. this.stopWatching();
  56. }
  57.  
  58. componentWillReceiveProps(nextProps) {
  59. if (nextProps.disabled) {
  60. this.stopWatching();
  61. } else {
  62. this.prevStatus = null;
  63. this.startWatching();
  64. }
  65. }
  66.  
  67. /**
  68. * 开始监听元素
  69. */
  70. startWatching() {
  71. if (this.interval) {
  72. return;
  73. }
  74.  
  75. this.interval = setInterval(() => {
  76. if (!this.viewPort) {
  77. return;
  78. }
  79.  
  80. this.viewPort.measure((x, y, width, height, pageX, pageY) => {
  81. const { rectBottom, verticalDirect: prevVerticalDirect } = this.state,
  82. offsetY = rectBottom - (pageY + height),
  83. verticalDirect = offsetY === 0 ? prevVerticalDirect : (offsetY > 0 ? DIRECTS.DOWN : DIRECTS.UP);
  84.  
  85. this.setState({
  86. rectTop: pageY,
  87. rectBottom: pageY + height,
  88. rectWidth: pageX + width,
  89. verticalDirect
  90. }, () => {
  91. this.isInViewPort();
  92. });
  93. });
  94. }, this.props.delay || 100);
  95. }
  96.  
  97. /**
  98. * 停止监听
  99. */
  100. stopWatching() {
  101. this.interval = clearInterval(this.interval);
  102. }
  103.  
  104. /**
  105. * 检查元素是否在视口中
  106. */
  107. isInViewPort() {
  108. const { onChange, type = 0 } = this.props,
  109. window = Dimensions.get('window'),
  110. { prevStatus, state } = this;
  111.  
  112. let isVisible;
  113.  
  114. switch (type) {
  115. case 0:
  116. isVisible = this.checkAll(state, window);
  117. break;
  118. case 1:
  119. isVisible = this.checkVerticalUp(state, window);
  120. break;
  121. case 2:
  122. isVisible = this.checkVerticalDown(state, window);
  123. break;
  124. case 3:
  125. isVisible = this.checkVertical(state, window);
  126. break;
  127. default:
  128. isVisible = false;
  129. }
  130.  
  131. if (prevStatus !== isVisible) {
  132. this.prevStatus = isVisible;
  133. onChange && onChange(isVisible);
  134. }
  135. }
  136.  
  137. /**
  138. * 检查元素在整个页面中是否出现
  139. * @param {object} state
  140. * @param {object} window
  141. */
  142. checkAll(state, window) {
  143. const { rectBottom, rectTop, rectWidth } = state,
  144. { height, width } = window;
  145.  
  146. return rectBottom &&
  147. rectTop >= 0 &&
  148. rectBottom <= height &&
  149. rectWidth > 0 &&
  150. rectWidth <= width;
  151. }
  152.  
  153. /**
  154. * 检查元素在垂直方向是否出现在视口中,从下向上滑动
  155. * @param {object} state
  156. * @param {object} window
  157. */
  158. checkVerticalUp(state, window) {
  159. const { rectBottom, rectTop, verticalDirect } = state,
  160. { height } = window;
  161.  
  162. return rectBottom &&
  163. rectTop >= 0 &&
  164. verticalDirect === DIRECTS.DOWN &&
  165. rectBottom <= height;
  166. }
  167.  
  168. /**
  169. * 检查元素在垂直方向是否出现在视口中,从上向下滑动
  170. * @param {object} state
  171. * @param {object} window
  172. */
  173. checkVerticalDown(state, window) {
  174. const { rectBottom, rectTop, verticalDirect } = state,
  175. { height } = window;
  176.  
  177. return rectBottom &&
  178. rectTop >= 0 &&
  179. verticalDirect === DIRECTS.UP &&
  180. rectBottom <= height;
  181. }
  182.  
  183. /**
  184. * 检查元素在垂直方向是否出现在视口中
  185. * @param {object} state
  186. * @param {object} window
  187. */
  188. checkVertical(state, window) {
  189. const { rectBottom, rectTop } = state,
  190. { height } = window;
  191.  
  192. return rectBottom &&
  193. rectTop >= 0 &&
  194. rectBottom <= height;
  195. }
  196.  
  197. render() {
  198. return (
  199. <View
  200. collapsable={false}
  201. ref={component => {
  202. this.viewPort = component;
  203. }}
  204. {...this.props}>
  205. {this.props.children}
  206. </View>
  207. );
  208. }
  209. }
Add Comment
Please, Sign In to add comment