1. 程式人生 > >【共享單車】—— React後臺管理系統開發手記:Router 4.0路由實戰演練

【共享單車】—— React後臺管理系統開發手記:Router 4.0路由實戰演練

前言:以下內容基於React全家桶+AntD實戰課程的學習實踐過程記錄。最終成果github地址:https://github.com/66Web/react-antd-manager,歡迎star。


 一、React Router 4.0核心概念

     4.0版本中已不需要路由配置,一切皆元件

  • react-router:基礎路由包
  1. 提供了一些router的核心api,包括Router,Route,Switch等
  • react-router-dom:基於瀏覽器的路由(包含react-router)
  1. 提供了BrowerRouter,HashRouter,Route,Link,NavLink
  2. 安裝:
    npm install react-router-dom --save
    //或
    yarn add react-router-dom  

     react-router-dom核心用法

  • HashRouter和BrowserRouter區別
  1. HashRouter
    http://localhost:3000/#/admin/buttons  
  2. BrowserRouter
    http://localhost:3000/admin/buttons
    
  • Route用法
  1. path屬性:路由地址
  2. component屬性:路由對應要跳轉到的元件
  3. exact屬性:代表精準匹配,必須path完全匹配才可以載入對應元件
  4. render方法:渲染一個元件,其中包裹一個子路由
    <Route path="/admin/ui/buttons" component={Button} /> 
    
    <Route path="/admin" render={() => 
    
         <Admin>
              <Route path="/admin/home"  component={Home} />
         </Admin>
    }/>
    
  • 導航
  1. NavLink:選單裡的導航;Link:超連結導航
  2. to:可以傳一個字串,也可以傳一個location物件
    import {Link} from 'react-router-dom';
    
    const Header=()=>{
        <header>
            <nav>
                <li><Link to='/'>Home</Link></li>
                <li><Link to='/about'>About</Link></li>
                <li><Link to='/three'>Three</Link></li>
            </nav>
        </header>
    }    
    
    <Link to={{pathname:'/three/7'}}>Three #7</Link> 
  3. 定義:<Route path="/three/:number" /> 

  4. 取值:this.props.match.params.number

  5. 一個基本的location物件: {  pathname: '/',  search:'',  hash:'',  key:'abc123',  state:{} }

  • Switch 選擇

  1. 選擇符合要求的Route,自上至下找到一個可以匹配的內容則不繼續載入其他 

  2. <Switch>是唯一的因為它僅僅只會渲染一個路徑
    <Switch>
        <Route path='/admin/ui/buttons' component={Buttons}/>
        <Route path='/admin/ui/models' component={Models}/>
        <Route path='/admin/ui/loading' component={Loading}/>
    </Switch>
    
  • Redirect 重定向

    <Redirect to="/admin/home">

二、React Router4.0 Demo介紹

巢狀路由 動態路由

     混合組件化 -- 將Route和Link放到同一個頁面 

  • HashRouter將Link和Router進行包裹,其內部必須只能有一個子節點
  • 渲染對應component中的元件
  1. 通過Link元件的to屬性設定路由地址
  2. 通過Route元件的path屬性匹配路由地址
  • 注意:Route新增exact屬性可以做到【路徑精準匹配】,否則/about既可以匹配 也可以匹配 /about 等路由地址

     Demo程式碼

  • Home.js:顯示整個頁面內容
    import React from 'react';
    import {HashRouter,Route,Link,Switch} from 'react-router-dom'
    import Main from './Main';
    import About from './About';
    import Topics from './Topics';
    
    class Home extends React.Component{
      render(){
          return(
              <HashRouter>
                  <div>
                      <ul>
                          <li>
                              <Link to="/">Home</Link>
                          </li>
                          <li>
                              <Link to="/about">About</Link>
                          </li>
                          <li>
                              <Link to="/topics">Topics</Link>
                          </li>
                      </ul>
                      <hr></hr>
                      <Switch>
                          <Route path="/" exact={true} component={Main}></Route>
                          <Route path="/about" component={About}></Route>
                          <Route path="/topics" component={Topics}></Route>
                      </Switch>
                  </div>   
              </HashRouter>
          );
      }
    }
    export default Home; 

    Main.js :路由元件 (其它元件同Main.js)

    import React,{Component} from 'react';
    class Main extends Component{
      render(){
          return(
              <div>
                  this is Main.
              </div>
          );
      }
    }
    export default Main;

    index.js:將Home元件掛載到根節點上

    import Home from './pages/router_demo/Home'
    
    ReactDOM.render(<Home />, document.getElementById('root'));

     配置化 -- 將Route路由提取到一個單獨的JS檔案中 

  • Router、Link和Route
  1. Router是節點 ——下面只能包含一個盒子標籤,如這裡的div,內容為路由及路由元件
    <Router>
         <div>
            //otherCoding
         </div>
    </Router>  
  2. Link是連結 —— 在html介面中會解析成a標籤,to代表連結地址(一個相對路徑 ) 
    <Router>
         <div>
            <ul>
               <li><link to='/'>首頁</Link></li>
               <li><link to='/other'>其他頁</Link></li>
            </ul>
         </div>
    </Router>
  3. Route是路由元件 —— path代表路徑,component代表路徑所對應的介面

    <Router>
          <div>
              <ul>
                  <li><Link to="/home">首頁</Link></li>
                  <li><Link to="/other">其他頁</Link></li>
              </ul>
              <Route path="/home" component={Home}/>
              <Route path="/other" component={Other}/>
          </div>
    </Router>
    
  • 配置化實現路由功能

  1. router.js:根據Home.js中的Link導航配置找到對應的元件
    import React from 'react'
    import {HashRouter as Router,Route} from 'react-router-dom' 
    import Main from './Main';
    import About from './About';
    import Topics from './Topics';
    import Home from './Home'
    
    export default class IRouter extends React.Component{
    
        render(){
            return (
                <Router>
                    <Home>
                        {/*根據導航配置找到對應的元件*/}
                        <Route path="/" exact={true} component={Main}></Route>
                        <Route path="/about" component={About}></Route>
                        <Route path="/topics" component={Topics}></Route>
                    </Home>
                </Router>
            )
        }
    }  
  2. Home.js:①頁面中配置Link導航  ②在router.js中通過Route找到元件  ③呈現在{this.props.children}處

    import React from 'react';
    import {Link} from 'react-router-dom'
    
    class Home extends React.Component{
      render(){
          return( 
                  <div>
                      {/*頁面導航的配置*/}
                      <ul>
                          <li>
                              <Link to="/">Home</Link>
                          </li>
                          <li>
                              <Link to="/about">About</Link>
                          </li>
                          <li>
                              <Link to="/topics">Topics</Link>
                          </li>
                      </ul>
                      <hr />
                      {/*找到路由匹配的元件後呈現的位置*/}
                      {this.props.children}  
                  </div> 
          );
      }
    }
    export default Home;   
  3. index.js:將router元件掛載到根節點上
    import Router from './pages/router_demo/router'
    
    ReactDOM.render(<Router />, document.getElementById('root'));
    
  • 巢狀路由 

  1. router.js:使用render方法渲染Main主頁面極其巢狀路由;注意箭頭函式後不能加{},否則只執行,並不會返回(return)

    import User from './User';
    
    {/*改變Main路由,新增render方法*/}
     <Route path="/main" render={() => 
            <Main>
                  <Route path="/main/user" component={User}></Route>
            </Main>
     }></Route>  
  2. Main.js:使用Link配置子路由導航,同時設定子路由顯示的位置{this.props.children}

    import {Link} from 'react-router-dom'
    
    {/*新增Link配置子路由導航*/}
    <Link to='/main/user'>巢狀路由</Link>
    <hr />
    {this.props.children}  
  3. 坑:因為前面main元件的路由添加了exact={true}精確匹配,會導致/user不被匹配,無法獲取子路由
  4. 解決:去掉exact屬性,使用/main匹配main元件路由,/main/user匹配user子元件路由
  • 獲取動態路由的值
  1. Main.js:設定跳轉的路由連結
    <Link to='/main/test-id'>動態路由1</Link>
    <br />
    <Link to='/main/456'>動態路由2</Link>
  2. router.js:新增動態路由,即path:"/main/:value"用冒號定義的路由內容

    import Info from './Info';
    
    {/*用冒號定義路由內容*/}
    <Route path="/main" render={() => 
         <Main>
                <Route path="/main/:value" component={Info}></Route>
         </Main>
    }></Route>
  3. Info.js:獲取定義的動態路由內容資訊,通過{this.props.match.params.路由的名稱}
    import React,{Component} from 'react';
    class Info extends Component{
      render(){
          return(
              <div>
                  這裡是測試動態路由功能
                  動態路由的值時:{this.props.match.params.value}
              </div>
          );
      }
    }
    export default Info;
    
  • 匹配路由的404頁面

  1. router.js:新增沒有path屬性的Route元件放置Switch元件內部的最後位置,作為預設路由

    import {HashRouter as Router,Route,Switch} from 'react-router-dom'
    import NoMatch from './NoMatch'
    
    <Switch>
           {/*Switch元件從上到下,只匹配一個路由*/}
           <Route path="/main" render={() => 
                  <Main>
                       <Route path="/main/:value" component={Info}></Route>
                  </Main>
           }></Route>
           <Route path="/about" component={About}></Route>
           <Route path="/topics" component={Topics}></Route>
           <Route component={NoMatch}></Route>
    </Switch>
  2. NoMatch.js

    import React from 'react';
    class NoMatch extends React.Component{
        render(){
            return(
                <div>
                    404 Not Found
                </div>
            );
        }
    }
    export default NoMatch;
    

三、專案路由實戰開發

  • index.js:掛載Router元件到根節點
    // import Admin from './admin'
    import Router from './router'
    
    ReactDOM.render(<Router />, document.getElementById('root'));
    
  • App.js:專案路由入口檔案

  1. 使用者訪問專案時輸入url對應的作為整個檔案輸出,一共有三種情況:登入、詳情頁、首頁
  2. App.js內部什麼都沒有,只有{this.props.children},主要用來存放子元件(即上述三個頁面),否則沒有顯示位置
    /**路由入口元件 */
    
    import React, { Component } from 'react';
    import './App.css';
    
    class App extends Component {
      render() {
        return (
            <div>
               {this.props.children}
            </div>
        );
      }
    }
    
    export default App;
    
  3. 總結:想利用Route顯示元件資訊,則必須有調動{this.props.children}顯示其頁面的元件

  • src->router.js:有三個頁面就需要有三個路由

  1. path為/login渲染登入元件

  2. path為/admin渲染首頁:①用render函式返回子路由Admin元件 ②定義巢狀路由/admin/ui/buttons顯示元件按鈕 ③無path顯示404頁面 ④外層用Switch包裹保證只顯示其中第一個匹配的Route
  3. path為/order/detail渲染詳情頁

    import React from 'react'
    import {HashRouter, Route, Switch} from 'react-router-dom'
    import App from './App'
    import Login from './pages/Login'
    import NoMatch from './pages/NoMatch'
    import Admin from './admin'
    import Buttons from './pages/ui/buttons'
    
    export default class IRouter extends React.Component{
    
        render() {
            return (
               <HashRouter>
                   <App>
                      <Route path="/login" component={Login}></Route>
                      <Route path="/admin" render={() => 
                          <Admin>
                              <Switch>
                                <Route path="/admin/ui/buttons" component={Buttons}></Route>
                                <Route component={NoMatch}></Route>
                              </Switch>
                          </Admin>
                      }></Route>
                     <Route path="/order/detail" component={Login}></Route>
                   </App>
               </HashRouter>
            )
        }
    }
  • src->admin.js:content部分使用{this.props.children}顯示在router.js中Route得到的頁面
    <Row className="content">
         {/* <Home /> */}
         {this.props.children}   
    </Row> 
  • NevLeft->index.js:通過左側導航欄進行跳轉
  1. 有Route就一定要有Link指定路由地址
  2. 利用react-router-dom的NavLink設定路由地址,NavLink元件顯示的內容為{item.title},to跳轉的地址為{item.key}
    import {NavLink} from 'react-router-dom'
    
    return <Menu.Item title={item.title} key={item.key}>
                     <NavLink to={item.key}>{item.title}</NavLink>
           </Menu.Item>
    
  • pages->ui->button.js:匹配的是/admin/ui/buttons則將Button元件渲染到Admin元件的content中

    import React,{Component} from 'react';
    class Buttons extends Component{
      render(){
          return(
              <div>
                  this is Buttons.
              </div>
          );
      }
    }
    export default Buttons;
  • pages->NoMatch->index.js:沒有對應的路由匹配則將404頁面渲染到Admin元件的content中

    import React,{Component} from 'react';
    class NoMatch extends Component{
      render(){
          return(
              <div style={{textAlign: 'center', fontSize:'24'}}>
                  404 No Found !!!
              </div>
          );
      }
    }
    export default NoMatch;

注:專案來自慕課網