製做一個命令式的 React 彈出層組件 (適用 React Native)

對於彈出層組件,React Portals 無疑是提供了一種很好的解決方案(Protal相關也能夠看這裏)。 若是沒有 Portal的話彈出層要怎麼處理呢,好比React Native環境中?html

React Native中可使用Modal組件,可是由於層級問題以及與其餘組件的兼容性也是常常被詬病。react

咱們來解決這個問題。函數

曲徑通幽


Modal的本質就是一個在組件樹上擁有更高顯示層級的view,能夠覆蓋整個頁面,有背景色和透明度,蒙層背景中包含彈出的顯示內容區,好比一個提示,對話框等等。佈局

將蒙層的Modal和內容區分開,作成父子組件的組合模式,自定義並暴露顯示子組件的方法,將子組件整個傳入Modal中顯示,便可達到彈出內容的效果,再提供關閉Modal的方法,用於命令式地設置Modal的隱藏。測試

也就是說咱們的組件知足這些條件:flex

  • 更高的顯示層級
  • 經過方法填入子組件,並暴露顯示和隱藏Modal的方法

實現和效果


命令式的調用無疑須要用到Ref了,開始實現:設計

  1. 定義組件。包含兩個state,一個view,一個控制顯示與隱藏的flag。暴露出兩個方法,顯示和關閉。須要顯示的內容view經過方法參數傳入code

    import React, { useImperativeHandle, useState } from "react";
    
    function Modal(props, ref) {
      const [view, setView] = useState([]);
      const [isShow, setIsShow] = useState(0);
    
      useImperativeHandle(ref, () => ({
        init: (view) => {
          setView(view);
          setIsShow(true);
        },
        close: () => setIsShow(false),
      }));
    
      if (isShow) {
        return <div style={sts.wrap}>{view}</div>;
      } else {
        return null;
      }
    }
    
    export default React.forwardRef(Modal);
    export const modalRef = React.createRef();
    export const TopModal = { show, close };
    
    function show(view) {
      modalRef.current.init(view);
    }
    function close() {
      modalRef.current.close();
    }
    
    // 蒙層 style
    const sts = {
      wrap: {
        zIndex: 100,
        top: 0,
        left: 0,
        width: "100%",
        height: "100%",
        position: "absolute",
        backgroundColor: "rgba(0,0,0,0.6)",
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
      },
    };
  2. 將組件放到組件樹較高層級的位置,這裏直接放到了和App同級的位置,將定義的Ref傳入。component

    import Modal, { modalRef } from "./refmodal/component";
    
    ReactDOM.render(
      <React.StrictMode>
        <App />
        <Modal ref={modalRef} />
      </React.StrictMode>,
      document.getElementById("root")
    );
  3. 測試運行效果。htm

    export default function ModalRefTest() {
      function openModal() {
        const view = (
          <div style={{ width: 100, height: 100, backgroundColor: "#FFF" }}>
            <button onClick={close}>關閉</button>
          </div>
        );
        TopModal.show(view);
      }
      function close() {
        TopModal.close();
      }
      return (
        <div>
          <button onClick={openModal}>打開</button>
        </div>
      );
    }

    彈出框的內容很簡單,只有一個按鈕,用於關閉當前Modalshow方法將內容區整個div傳入。

    效果:

到這裏,一個簡易版本的Modal已經有了初步效果。

擴展方向


將要顯示的內容作成一個組件,直接將組件view傳入Modal中顯示。這樣的方式,能夠作成對話框,Toast,各類提示。這其中可能還須要對背景色做出修改,這些也能夠經過函數參數的方式傳入到組件中來處理。

也能夠將佈局的關鍵屬性傳入,組件決定內容區顯示在中間仍是頂部,仍是底部。由此再能夠擴展出actionSheet組件。

能夠將API設計成show(view,config)的形式,讀取config的內容,動態設置樣式和佈局顯示。

經過React的方式添加的高層級view顯示,這一思路徹底適用於React Native

相關文章
相關標籤/搜索