【共享單車】—— React後臺管理系統開發手記:Router 4.0路由實戰演練
前言:以下內容基於React全家桶+AntD實戰課程的學習實踐過程記錄。最終成果github地址:https://github.com/66Web/react-antd-manager,歡迎star。
一、React Router 4.0核心概念
4.0版本中已不需要路由配置,一切皆元件
- react-router:基礎路由包
- 提供了一些router的核心api,包括Router,Route,Switch等
- react-router-dom:基於瀏覽器的路由(包含react-router)
- 提供了BrowerRouter,HashRouter,Route,Link,NavLink
- 安裝:
npm install react-router-dom --save //或 yarn add react-router-dom
react-router-dom核心用法
- HashRouter和BrowserRouter區別
- HashRouter
http://localhost:3000/#/admin/buttons
- BrowserRouter
http://localhost:3000/admin/buttons
- Route用法
- path屬性:路由地址
- component屬性:路由對應要跳轉到的元件
- exact屬性:代表精準匹配,必須path完全匹配才可以載入對應元件
- render方法:渲染一個元件,其中包裹一個子路由
<Route path="/admin/ui/buttons" component={Button} />
<Route path="/admin" render={() => <Admin> <Route path="/admin/home" component={Home} /> </Admin> }/>
- 導航
- NavLink:選單裡的導航;Link:超連結導航
- 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>
-
定義:<Route path="/three/:number" />
-
取值:this.props.match.params.number
-
一個基本的location物件: { pathname: '/', search:'', hash:'', key:'abc123', state:{} }
-
Switch 選擇
-
選擇符合要求的Route,自上至下找到一個可以匹配的內容則不繼續載入其他
- <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中的元件
- 通過Link元件的to屬性設定路由地址
- 通過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
- Router是節點 ——下面只能包含一個盒子標籤,如這裡的div,內容為路由及路由元件
<Router> <div> //otherCoding </div> </Router>
- Link是連結 —— 在html介面中會解析成a標籤,to代表連結地址(一個相對路徑 )
<Router> <div> <ul> <li><link to='/'>首頁</Link></li> <li><link to='/other'>其他頁</Link></li> </ul> </div> </Router>
-
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>
-
配置化實現路由功能
- 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> ) } }
-
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;
- index.js:將router元件掛載到根節點上
import Router from './pages/router_demo/router' ReactDOM.render(<Router />, document.getElementById('root'));
-
巢狀路由
-
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>
-
Main.js:使用Link配置子路由導航,同時設定子路由顯示的位置{this.props.children}
import {Link} from 'react-router-dom' {/*新增Link配置子路由導航*/} <Link to='/main/user'>巢狀路由</Link> <hr /> {this.props.children}
- 坑:因為前面main元件的路由添加了exact={true}精確匹配,會導致/user不被匹配,無法獲取子路由
- 解決:去掉exact屬性,使用/main匹配main元件路由,/main/user匹配user子元件路由
- 獲取動態路由的值
- Main.js:設定跳轉的路由連結
<Link to='/main/test-id'>動態路由1</Link> <br /> <Link to='/main/456'>動態路由2</Link>
-
router.js:新增動態路由,即
path:"/main/:value"
用冒號定義的路由內容import Info from './Info'; {/*用冒號定義路由內容*/} <Route path="/main" render={() => <Main> <Route path="/main/:value" component={Info}></Route> </Main> }></Route>
- 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頁面
-
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>
-
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:專案路由入口檔案
- 使用者訪問專案時輸入url對應的作為整個檔案輸出,一共有三種情況:登入、詳情頁、首頁
-
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;
-
總結:想利用Route顯示元件資訊,則必須有調動
{this.props.children}
顯示其頁面的元件
-
src->router.js:有三個頁面就需要有三個路由
-
path為/login渲染登入元件
- path為/admin渲染首頁:①用render函式返回子路由Admin元件 ②定義巢狀路由/admin/ui/buttons顯示元件按鈕 ③無path顯示404頁面 ④外層用Switch包裹保證只顯示其中第一個匹配的Route
-
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:通過左側導航欄進行跳轉
- 有Route就一定要有Link指定路由地址
- 利用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;
注:專案來自慕課網