React-router 將彈框Modal嵌入路由(create a modal route with react-router)


 

 背景:

  在使用react-router時,我們往往只有在真實的需要頁面跳轉時,才會將頁面加入路由(Route)。對於彈框(Modal),卻總是會忽視它的路由需求。

  在開發者眼中: 彈框只是頁面中的附屬,無需單獨准備路由存放。當然,也有其他原因,比如我們想要一個公用的方法,以此來顯示彈框。諸如此類,導致開發時沒有正視彈框。

  可在用戶眼中: 彈框也是頁面,至少在想要返回的時候,移除彈框即可(不要把彈框下的頁面也給返回了)。

  因此,Modal彈框Route路由BackPress物理返回 三者間的微妙關系就變得尤為關鍵了

 

目的:

  用戶視角: 彈框顯示時,物理返回(手機返回操作、瀏覽器左上角回退按鈕),只隱藏彈框(不影響下層頁面內容,比如滾動、比如輸入框內容)

  開發者視角: 1. 原本的目的很簡單,只需要在有彈框顯示時,物理返回隱藏彈框的同時阻止下層頁面的返回

        2. 將彈框加入路由,彈框即頁面,會被路由同等對待

 

幾次嘗試:

  1. 使用 popstate 監聽

window.addEventListener("popstate", () => {});

  2. 使用history.listen監聽

history.listen((newLocation, action) => {
    if(action === "PUSH) {

    } else {
        // 判斷是否存在彈框
        if(ReactDOM.findDOMNode(document.getElementById("modal"))) {
            // 隱藏彈框
       // 前進一個路由 history.go(1) } } })

注意: 以上方法均是通過監聽路由變化(popstate監聽、history.listen監聽),並輔以判斷彈框的顯示與否來確定。

此處使用的是history.go(1)前進一個路由,因為無法阻止在物理返回時的路由回退,只能通過  回退 - 判斷有彈框 - 前進 的流程進行

 

將Modal加進路由的嘗試:

方式一: 使用 <Route path="/" /> + this.props.location.search改變路由
- 特點: 通過跳轉路由,在原有url上增加"?login=true",PUSH路由,以此判斷識別是否顯示指定內容
//  - Router.js中使用: 
    <BrowserRouter>
        <Switch>
            ...
        </Switch>
        <Route path="/" component={Login}>
    </BrowserRouter>

//  - 顯示Modal(跳轉Login路由):
    <Linl to={{pathname: this.props.match.url, search: "?login=true"}}>To Login</Link>

//  - Login.js中使用
    render() {
        let params = new URLSearchParams(this.props.location.search);
        return(
            params.get("login") && (<Modal>...</Modal>)
        )
    } 

 

方式二: 在需要頁面增加<Route>節點 + path={this.props.match.url + "/modal"} + React.createPortal(<div>...</div>, #modal_root) + index.html中的 <div id="modal_root"></div>
- 特點: 在需要的頁面增加<Route>節點,且Route的path為當前url(即this.props.match.url) + "/modal",另外Route的渲染內容(render)和通過React.createPortal和外部index.html的<div id="modal_root"></div>關聯
//  - 需要顯示Modal的 profile.js
    <Link to={this.props.match.url + "/modal"}>Show Modal</Link>

    <Route
        path={this.props.match.url + "/modal"}
        render={() => {
            return (
                <Modal onClick={() => this.props.history.goBack()}>
                    ...
                </Modal>
            )
        }}
    />
  
//  - Modal.js 內容:
    render() {
        return React.createPortal(
            <div onClick={this.props.onClick}>
                ...
            </div>
        )
    }

 

最終使用的方法

 1. 使用路由跳轉(本處使用的search),但是僅僅跳轉,路由中沒有實際內容;
    2. 原本的Modal顯示不變方式;
    3. 在Modal的show()方法中,增加history.push({pathname: this.props.match.url, search: "?modal=true"});
    4. 增加 history.listen監聽,判斷帶有相應search的路由回退,即可關閉想要Modal;
    5. 在Modal的hide()方法中,增加history.go(-1),在Modal隱藏時,回退路由。

 

引用:

title: Create a Modal Route with React Router

author: Jason Brown

url: https://codedaily.io/tutorials/77/Create-a-Modal-Route-with-React-Router

github: https://github.com/codedailyio/ReactRouterModal


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM