Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * @File 检查元素是否在视口中
- * @Author: yabingzyb.zhang
- * @Date: 2018-10-16 15:45:13
- * @Last Modified by: yabingzyb.zhang
- * @Last Modified time: 2018-10-16 17:43:12
- */
- import React, { Component, PropTypes } from 'react';
- import { View, Dimensions } from 'react-native';
- // 滑动方向
- const DIRECTS = {
- UP: 'UP',
- DOWN: 'DOWN'
- };
- export default class extends Component {
- static propTypes = {
- // 检查元素出现的方向:0: 所有方向,1:从下向上,2:从上向下,3:垂直方向
- type: PropTypes.number,
- // 检测元素位置间隔
- delay: PropTypes.number,
- // 状态发生变化时的回调
- onChange: PropTypes.func.isRequired,
- // 是否停止监听
- disabled: PropTypes.bool
- };
- static defaultProps = {
- type: 0,
- delay: 100,
- disabled: false,
- onChange: () => { }
- };
- constructor(props) {
- super(props);
- this.state = {
- rectTop: 0,
- rectBottom: 0,
- verticalDirect: ''
- };
- this.viewPort = null;
- }
- componentDidMount() {
- if (!this.props.disabled) {
- this.startWatching();
- }
- }
- componentWillUnmount() {
- this.stopWatching();
- }
- componentWillReceiveProps(nextProps) {
- if (nextProps.disabled) {
- this.stopWatching();
- } else {
- this.prevStatus = null;
- this.startWatching();
- }
- }
- /**
- * 开始监听元素
- */
- startWatching() {
- if (this.interval) {
- return;
- }
- this.interval = setInterval(() => {
- if (!this.viewPort) {
- return;
- }
- this.viewPort.measure((x, y, width, height, pageX, pageY) => {
- const { rectBottom, verticalDirect: prevVerticalDirect } = this.state,
- offsetY = rectBottom - (pageY + height),
- verticalDirect = offsetY === 0 ? prevVerticalDirect : (offsetY > 0 ? DIRECTS.DOWN : DIRECTS.UP);
- this.setState({
- rectTop: pageY,
- rectBottom: pageY + height,
- rectWidth: pageX + width,
- verticalDirect
- }, () => {
- this.isInViewPort();
- });
- });
- }, this.props.delay || 100);
- }
- /**
- * 停止监听
- */
- stopWatching() {
- this.interval = clearInterval(this.interval);
- }
- /**
- * 检查元素是否在视口中
- */
- isInViewPort() {
- const { onChange, type = 0 } = this.props,
- window = Dimensions.get('window'),
- { prevStatus, state } = this;
- let isVisible;
- switch (type) {
- case 0:
- isVisible = this.checkAll(state, window);
- break;
- case 1:
- isVisible = this.checkVerticalUp(state, window);
- break;
- case 2:
- isVisible = this.checkVerticalDown(state, window);
- break;
- case 3:
- isVisible = this.checkVertical(state, window);
- break;
- default:
- isVisible = false;
- }
- if (prevStatus !== isVisible) {
- this.prevStatus = isVisible;
- onChange && onChange(isVisible);
- }
- }
- /**
- * 检查元素在整个页面中是否出现
- * @param {object} state
- * @param {object} window
- */
- checkAll(state, window) {
- const { rectBottom, rectTop, rectWidth } = state,
- { height, width } = window;
- return rectBottom &&
- rectTop >= 0 &&
- rectBottom <= height &&
- rectWidth > 0 &&
- rectWidth <= width;
- }
- /**
- * 检查元素在垂直方向是否出现在视口中,从下向上滑动
- * @param {object} state
- * @param {object} window
- */
- checkVerticalUp(state, window) {
- const { rectBottom, rectTop, verticalDirect } = state,
- { height } = window;
- return rectBottom &&
- rectTop >= 0 &&
- verticalDirect === DIRECTS.DOWN &&
- rectBottom <= height;
- }
- /**
- * 检查元素在垂直方向是否出现在视口中,从上向下滑动
- * @param {object} state
- * @param {object} window
- */
- checkVerticalDown(state, window) {
- const { rectBottom, rectTop, verticalDirect } = state,
- { height } = window;
- return rectBottom &&
- rectTop >= 0 &&
- verticalDirect === DIRECTS.UP &&
- rectBottom <= height;
- }
- /**
- * 检查元素在垂直方向是否出现在视口中
- * @param {object} state
- * @param {object} window
- */
- checkVertical(state, window) {
- const { rectBottom, rectTop } = state,
- { height } = window;
- return rectBottom &&
- rectTop >= 0 &&
- rectBottom <= height;
- }
- render() {
- return (
- <View
- collapsable={false}
- ref={component => {
- this.viewPort = component;
- }}
- {...this.props}>
- {this.props.children}
- </View>
- );
- }
- }
Add Comment
Please, Sign In to add comment