计划 1 一般应用

在组件中间接创立 modal 显示:

const {useState, useMemo} = Reactconst useModal = () => {    const [visible, setVisible] = useState(false)    return useMemo(() => {        return {            visible,            show: () => {                setVisible(true)            },            close: () => {                setVisible(false)            }        }    }, [visible])}function App() {    const modal = useModal()    return <>        <button onClick={modal.show}>显示 modal        </button>        <Modal visible={modal.visible} close={modal.close}>qwerty</Modal>    </>}ReactDOM.render(<App/>,    document.getElementById('root'));

这里我应用了 hooks 的计划来创立 modal

modal 组件:

const stopPropagation = ev => ev.stopPropagation()/** * 点击 x 和 mask 的时候能够敞开 modal * @param props * @return {*|JSX.Element} * @constructor */function Modal1(props) {    return props.visible && <div onClick={props.close} className="modal-container">        <div className="modal-box" onClick={stopPropagation}>            <div className="modal-title">                <span>模态框</span>                <span className="modal-close-icon" onClick={props.close}>x</span>            </div>            {props.children}        </div>    </div>}

增加了整个 div 的 click 事件, 使得其在点击空白区域时能够触发 close 事件

应用这种办法增加 modal, 长处就是应用简略
然而须要在以后组件援用 modal, 不能缓存 modal

计划 2 指令式的调用

代码:

const {useRef} = Reactconst {body} = documentconst show = () => {    const Dom = document.createElement('div')    Dom.classList.add('modal-container')    body.appendChild(Dom)    const close = () => {        ReactDOM.unmountComponentAtNode(Dom)        body.removeChild(Dom)    }    ReactDOM.render(<Modal close={close}/>, Dom)}const showV2 = () => {    let Dom    if (!showV2.cacheDom) {        let _Dom = document.createElement('div')        _Dom.classList.add('modal-container')        body.appendChild(_Dom)        showV2.cacheDom = _Dom        Dom = _Dom    } else {        Dom = showV2.cacheDom        Dom.style.display = 'block'    }    const close = () => {        Dom.style.display = 'none'    }    ReactDOM.render(<Modal close={close}/>, Dom)}showV2.cacheDom = nullfunction App() {    return <>        <button onClick={show}>显示 modal        </button>        <button onClick={showV2}>显示 modal (缓存 modal)        </button>    </>}ReactDOM.render(<App/>,    document.getElementById('root'));

灵便应用 react-dom 的 api ReactDOM.renderReactDOM.unmountComponentAtNode
通过 api 给 dom 挂载(解除)咱们须要的组件
这样应用有 2 个次要的长处:

  1. 指令式调用, 不必在 组件里引入 modal 再申明一个状态值和显示/暗藏的办法来管制他,这些冗余的操作(尽管这些货色能够通过一些计划来解决,然而仍旧很麻烦)
  2. 能够缓存 modal, 在第二次调用时 只须要扭转 display 即可

在很多组件库里,这种写法是被常常用到的, 比方 ant-design 里的 message 和 modal(局部)

计划 3 应用 react 的 api 强化计划1

这里须要说到的是 react 的 api : createPortal, 官网链接: https://zh-hans.reactjs.org/d...

来自官网的一句简略介绍: Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优良的计划

其实用起来和计划一 是差不多的,关键在于 modal 的代码不一样:

const {body} = documentfunction Modal(props) {    return ReactDOM.createPortal(        <div className="modal-container" style={{display: props.visible ? 'block' : 'none'}}>            <div className="modal-box">                <div className="modal-title">                    <span>模态框</span>                    <span className="modal-close-icon" onClick={props.close}>x</span>                </div>                {props.children}            </div>        </div>        , body)}

长处

  1. 事件冒泡, 在 Modal 里面尝试包裹一层 div, 再增加 click 事件监听:

    <div onClick={ev => {    console.log(ev, ev.target)}}>    <Modal visible={modal.visible} close={modal.close}/></div>

    在某些非凡状况下比拟不便, 能够将一些事件api裸露进去,并且也不影响外部

  2. 当父组件增加 overflow: hidden 或 z-index 时, modal 并不会被暗藏

这个长处当然是绝对于计划一来说的

总结

总结下 react 里根本就这几种根本计划, 如果有脱漏的中央也麻烦留个言告知下
这里放上这篇文章里的所有代码, 如果有帮忙到了你, 麻烦点下 star, 感激不尽
https://github.com/Grewer/JsD...