Home Reference Source Repository

src/components/portal/Portal.js

/**
 * @author haw
 */

import React, {
  PropTypes,
  Component,
  cloneElement
} from 'react';
import {
  render
} from 'react-dom';
import {
  createPortalEl,
  getContainer
} from '../util/dom';

/**
 * 为所有弹窗组件提供包裹容器,并控制弹窗是否显示
 */
export default class Portal extends Component {

  /**
   * 构造函数
   * @param {Object} props 组件所使用的属性
   * @param {boolean} props.visible 是否显示弹窗
   * @param {Object} context
   */
  constructor(props, context) {
    super(props, context);

    this.state = {
      visible: props.visible
    };
  }

  componentWillReceiveProps(nextProps) {
    this._setVisible(nextProps.visible);
  }

  _close = () => {
    this._setVisible(false);
  }

  _setVisible(visible) {
    this.setState({
      visible
    });
  }

  render() {
    let {
      children
    } = this.props;

    if (children) {
      children = cloneElement(children, {
        visible: this.state.visible,
        close: this._close
      });
    }
    return children || null;
  }
}

/**
 * 显示弹窗的 API 调用方法
 * @param {PropTypes.element} Component 弹窗组件
 * @param  {Object} props     @see Component 组件属性
 * @param  {Node} container 弹窗的容器节点
 */
Portal.show = (Component, props, container) => {
  container = getContainer(container);
  Component.portalEl = Component.portalEl || createPortalEl(container);

  return render((
    <Portal visible>
      <Component {...props} />
    </Portal>
  ), Component.portalEl);
};

Portal.propTypes = {
  visible: PropTypes.bool,
  children: PropTypes.node
};

Portal.defaultProps = {
  visible: false
};