React如何实现popover气泡卡片功能?

heath_learning
  • 1.3k

想用react实现类似antd的气泡卡片功能,但不知道怎么实现能同时将组件的子元素渲染出来,又能将气泡卡片的内容渲染在body中(React.createPortal可以将内容渲染到body中)。
popover.gif

要怎么才能实现上图这种效果呢?求大神指点

回复
阅读 3.8k
2 个回答

不要怀疑自己,我的校友,就是 React.createPortal()

挖了 antd 的坟,发现是 createPortal ,我还解决了这个问题:
🔥 如何优雅地解决多个 React、Vue App 之间的状态共享?

文档:https://reactjs.org/docs/port...
demo:https://codepen.io/gaearon/pe...

更新————————————————————————————

// These two containers are siblings in the DOM
const appRoot = document.getElementById('app-root')
const modalRoot = document.getElementById('modal-root')

class Modal extends React.Component {
  constructor(props) {
    super(props)
    this.el = document.createElement('div')
  }

  componentDidMount() {
    modalRoot.appendChild(this.el)
  }

  componentWillUnmount() {
    modalRoot.removeChild(this.el)
  }

  render() {
    return ReactDOM.createPortal(this.props.children, this.el)
  }
}

class Parent extends React.Component {
  constructor(props) {
    super(props)
    this.state = { clicks: 0, show: false }
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    // This will fire when the button in Child is clicked,
    // updating Parent's state, even though button
    // is not direct descendant in the DOM.
    this.setState((prevState) => ({
      clicks: prevState.clicks + 1,
      show: !prevState.show,
    }))
  }

  render() {
    return (
      <div onClick={this.handleClick}>
        <button>Open Modal</button>
        <p>Number of clicks: {this.state.clicks}</p>
        <p>
          Open up the browser DevTools to observe that the button is not a child of the div with the
          onClick handler.
        </p>

        {this.state.show ? (
          <Modal>
            <div className="modal">
              <p>Some contents...</p>
            </div>
          </Modal>
        ) : null}
      </div>
    )
  }
}

function Child() {
  // The click event on this button will bubble up to parent,
  // because there is no 'onClick' attribute defined
  return (
    <div className="modal">
      <button>Click</button>
    </div>
  )
}

ReactDOM.render(<Parent />, appRoot)

将上面代码粘贴至 https://codepen.io/gaearon/pe...
chrome-capture (14).gif

可以基于 React.createPortal() 。而且antd的底层也是这么干的

宣传栏