zoukankan      html  css  js  c++  java
  • 在 react 创建 modal

    方案 1 普通使用

    在组件中直接创建 modal 显示:

    const {useState, useMemo} = React
    
    const 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} = React
    const {body} = document
    
    const 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 = null
    
    function 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/docs/portals.html

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

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

    const {body} = document
    function 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/JsDemo/tree/master/reactModal

  • 相关阅读:
    WampServer Mysql配置
    Java实现 蓝桥杯VIP 算法提高 陶陶摘苹果2
    Java实现 蓝桥杯VIP 算法提高 陶陶摘苹果2
    Java实现 蓝桥杯VIP 算法提高 陶陶摘苹果2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 前10名
  • 原文地址:https://www.cnblogs.com/Grewer/p/13837973.html
Copyright © 2011-2022 走看看