對於彈出層組件,React Portals 無疑是提供了一種很好的解決方案(Protal相關也能夠看這裏)。 若是沒有 Portal
的話彈出層要怎麼處理呢,好比React Native
環境中?html
React Native
中可使用Modal
組件,可是由於層級問題以及與其餘組件的兼容性也是常常被詬病。react
咱們來解決這個問題。函數
Modal
的本質就是一個在組件樹上擁有更高顯示層級的view
,能夠覆蓋整個頁面,有背景色和透明度,蒙層背景中包含彈出的顯示內容區,好比一個提示,對話框等等。佈局
將蒙層的Modal
和內容區分開,作成父子組件的組合模式,自定義並暴露顯示子組件的方法,將子組件整個傳入Modal
中顯示,便可達到彈出內容的效果,再提供關閉Modal
的方法,用於命令式地設置Modal
的隱藏。測試
也就是說咱們的組件知足這些條件:flex
Modal
的方法命令式的調用無疑須要用到Ref
了,開始實現:設計
定義組件。包含兩個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", }, };
將組件放到組件樹較高層級的位置,這裏直接放到了和App
同級的位置,將定義的Ref
傳入。component
import Modal, { modalRef } from "./refmodal/component"; ReactDOM.render( <React.StrictMode> <App /> <Modal ref={modalRef} /> </React.StrictMode>, document.getElementById("root") );
測試運行效果。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> ); }
彈出框的內容很簡單,只有一個按鈕,用於關閉當前Modal
,show
方法將內容區整個div
傳入。
效果:
到這裏,一個簡易版本的Modal
已經有了初步效果。
將要顯示的內容作成一個組件,直接將組件view
傳入Modal
中顯示。這樣的方式,能夠作成對話框,Toast,各類提示。這其中可能還須要對背景色做出修改,這些也能夠經過函數參數的方式傳入到組件中來處理。
也能夠將佈局的關鍵屬性傳入,組件決定內容區顯示在中間仍是頂部,仍是底部。由此再能夠擴展出actionSheet
組件。
能夠將API
設計成show(view,config)
的形式,讀取config
的內容,動態設置樣式和佈局顯示。
經過React
的方式添加的高層級view
顯示,這一思路徹底適用於React Native
。