React Navigation源代码阅读 :views/CardStack/PointerEventsContainer.js

import React from 'react';
import invariant from '../../utils/invariant';
import AnimatedValueSubscription from '../AnimatedValueSubscription';

const MIN_POSITION_OFFSET = 0.01;

/**
 * Create a higher-order component that automatically computes the
 * `pointerEvents` property for a component whenever navigation position
 * changes.
 *
 * 该文件定义并导出了这样一个高阶组件(HOC):
 * 1. 这是一个容器组件 Container ;
 * 2. 这个容器组件 Container 只封装一个传入的组件 Component ,也只渲染这个组件 ;
 * 3. 一旦导航位置 navigation position 发生变化,会重新计算属性 pointerEvents
 *    并设置到所封装的组件 Component ;
 *
 */
export default function create(Component) {
    class Container extends React.Component {
        constructor(props, context) {
            super(props, context);
            this._pointerEvents = this._computePointerEvents();
        }

        componentWillMount() {
            this._onPositionChange = this._onPositionChange.bind(this);
            this._onComponentRef = this._onComponentRef.bind(this);
        }

        componentDidMount() {
            // 组件挂载时绑定 props.position 动画值变化监听器
            this._bindPosition(this.props);
        }

        componentWillUnmount() {
            // 组件将要卸载时删除 props.position 动画值变化监听器
            this._positionListener && this._positionListener.remove();
        }

        componentWillReceiveProps(nextProps) {
            // 当前组件的属性发生变化时重新绑定对属性 props.position 动画值
            // 的变化监听
            this._bindPosition(nextProps);
        }

        render() {
            this._pointerEvents = this._computePointerEvents();
            return (
                <Component
                    {...this.props}
                    pointerEvents={this._pointerEvents}
                    onComponentRef={this._onComponentRef}
                />
            );
        }

        _onComponentRef(component) {
            this._component = component;
            if (component) {
                invariant(
                    typeof component.setNativeProps === 'function',
                    'component must implement method `setNativeProps`'
                );
            }
        }

        /**
         * 创建一个监听器,监听 props.position 动画值的变化,
         * 一旦有变化执行相应的逻辑 this._onPositionChange
         * @param props
         * @private
         */
        _bindPosition(props) {
            this._positionListener && this._positionListener.remove();
            this._positionListener = new AnimatedValueSubscription(
                props.position,
                this._onPositionChange
            );
        }

        /**
         * props.position 动画值的变化事件的响应处理逻辑
         * @private
         */
        _onPositionChange() {
            if (this._component) {
                const pointerEvents = this._computePointerEvents();
                if (this._pointerEvents !== pointerEvents) {
                    this._pointerEvents = pointerEvents;
                    this._component.setNativeProps({pointerEvents});
                }
            }
        }

        /**
         * 重新计算属性 Pointer Event
         * @returns {string}
         * @private
         */
        _computePointerEvents() {
            const {navigation, position, scene} = this.props;

            if (scene.isStale || navigation.state.index !== scene.index) {
                // The scene isn't focused.
                return scene.index > navigation.state.index ? 'box-only' : 'none';
            }

            const offset = position.__getAnimatedValue() - navigation.state.index;
            if (Math.abs(offset) > MIN_POSITION_OFFSET) {
                // The positon is still away from scene's index.
                // Scene's children should not receive touches until the position
                // is close enough to scene's index.
                return 'box-only';
            }

            return 'auto';
        }
    }

    return Container;
}

猜你喜欢

转载自blog.csdn.net/andy_zhang2007/article/details/80264227