本系列目錄
點贊是美德 : )
React 快速上手 – 07 前端路由 react-router
目標
- 基礎使用
- 引數傳遞
- 路由匹配
- 轉換動畫
- 跳轉路由
環境
- react 16
- react-router 4
- react-router-dom 4
- react-transition-group
0. 安裝
通過官網我們可以發現 react-router
可以用在 web 網站端
native 裝置端
我們這裡針對 web 網站端
安裝
yarn add react-router-dom
複製程式碼
react-router
會包自動依賴安裝
1. 先跑一個簡單例子
- 程式碼示範
import React, {Component} from `react`
import {HashRouter as Router, Route, Link, Switch} from `react-router-dom`
const Home = () => (
<div>
<h2>首頁</h2>
</div>
)
const About = () => (
<div>
<h2>關於</h2>
</div>
)
class RouterView extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">首頁</Link>
</li>
<li>
<Link to="/about">關於</Link>
</li>
</ul>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</div>
</Router>
)
}
}
export default RouterView
複製程式碼
- 程式碼結構
最外層需要包裹元件
<Router>
元件<Route>
就是你看到的元件內容,放在哪裡就哪裡顯示
元件<Link>
是頁面連結
- 動圖說明
- codepen
2. 基礎使用
2.1 BrowserRouter
還是 HashRouter
BrowserRouter
是需要服務端配合, 是基於html5的pushState和replaceState的,很多瀏覽器不支援,存在相容性問題。
連結地址長這樣
http://localhost:3000/about
HashRouter
是瀏覽器端解析路由
連結地址長這樣
http://localhost:3000#/about
- 靈活切換
import {HashRouter as Router, Route, Link, Switch} from `react-router-dom`
//import {BrowserRouter as Router, Route, Link, Switch} from `react-router-dom`
<Router>
...
</Router>
複製程式碼
我用
as Router
做了別名,方便切換
2.2 元件 <Route>
屬性 exact
完全匹配
<Route path="/about" component={About} />
複製程式碼
exact=false
的時候 path
等於 /about
/about/me
都能匹配
但是 exact=true
的時候 只匹配 path
等於 /about
2.3 元件 <Route>
屬性 strict
末尾斜槓的匹配
<Route strict path="/about/" component={About} />
複製程式碼
當 strict=true
路由請求末尾必須帶 /
2.4 元件 <Link>
生成路由連結
- 屬性
to: string
路由地址字串
<Link to="/about?me=haha">關於</Link>
複製程式碼
- 屬性
to: object
路由物件
<Link to={{
pathname: `/courses`,
search: `?sort=name`,
hash: `#the-hash`,
state: { fromDashboard: true }>關於</Link>
複製程式碼
- 屬性
replace: bool
設定 true
替換瀏覽器物件 history
為當前路由,按回退按鈕時會發現之前的路由被替換了
2.5 元件 <NavLink>
生成路由連結的基礎上,如果是當前路由設定啟用樣式
- 屬性
activeClassName: string
樣式名稱
<NavLink to="/about" activeClassName="selected">關於</NavLink>
複製程式碼
- 屬性
activeStyle: object
樣式物件
<NavLink to="/about" activeStyle={{
fontWeight: `bold`,
color: `red`
}}>關於</NavLink>
複製程式碼
- 屬性
isActive: func
判斷函式
const checkIsActive = (match, location) => {
if (!match) {
return false
}
...
return true
}
<NavLink to="/about" isActive={checkIsActive}>關於</NavLink>
複製程式碼
2.6 元件 <Switch>
只渲染出第一個與當前訪問地址匹配的 <Route>
或 <Redirect>
否則你有幾個 <Route>
都會顯示
2.7 元件 <Redirect>
路由重定向
<Switch>
<Redirect from=`/users/:id` to=`/users/profile/:id`/>
<Route path=`/users/profile/:id` component={Profile}/>
</Switch>
複製程式碼
當請求 /users/:id
被重定向去 `/users/profile/:id`
- 屬性
from: string
需要匹配的將要被重定向路徑。
- 屬性
to: string
重定向的 URL 字串
- 屬性
to: object
重定向的 location 物件
- 屬性
push: bool
若為真,重定向操作將會把新地址加入到訪問歷史記錄裡面,並且無法回退到前面的頁面。
2.8 元件 <Prompt>
當使用者離開當前頁面前做出一些提示。
- 屬性
message: string
當使用者離開當前頁面時,設定的提示資訊。
<Prompt message="確定要離開?" />
複製程式碼
- 屬性
message: func
當使用者離開當前頁面時,設定的回掉函式
<Prompt message={location => `確定要去 ${location.pathname} ?`} />
複製程式碼
- 屬性
when: bool
決定是否啟用 Prompt
3. 引數傳遞
3.1 編寫路由定義
<Route path="/topics/:topicId" component={Topic} />
複製程式碼
:topicId
定義引數
3.2 編寫接收元件
const Topic = ({match}) => (
<div>
<h3>引數: {match.params.topicId}</h3>
</div>
)
複製程式碼
match.params
就是傳遞的引數
3.3 完整例子
程式碼
import React, {Component} from `react`
import {BrowserRouter as Router, Route, Link, Switch} from `react-router-dom`
const Topic = ({match}) => (
<div>
<h3>引數: {match.params.topicId}</h3>
</div>
)
class RouterView extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/topics/rendering">Rendering with React</Link>
</li>
<li>
<Link to="/topics/components">Components</Link>
</li>
<li>
<Link to="/topics/props-v-state">Props v. State</Link>
</li>
</ul>
<Switch>
<Route path="/topics/:topicId" component={Topic} />
</Switch>
</div>
</Router>
)
}
}
export default RouterView
複製程式碼
動圖效果
4. 沒有匹配
程式碼
import React, {Component} from `react`
import {BrowserRouter as Router, Route, Link, Switch} from `react-router-dom`
const Back = () => (
<div>
<h2>首頁</h2>
</div>
)
const NoMatch = () => (
<div>
<h2>沒有匹配</h2>
</div>
)
class RouterView extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/back">返回</Link>
</li>
<li>
<Link to="/also/will/not/match">路由請求</Link>
</li>
</ul>
<Switch>
<Route path="/back" component={Back} />
<Route component={NoMatch} />
</Switch>
</div>
</Router>
)
}
}
export default RouterView
複製程式碼
在最下面寫個預設元件,都沒命中,就是這個了
動圖效果
5. 巢狀路由
在 react-route4
中巢狀要這樣寫
<Switch>
<Route path="/article" component={ArticleList} />
<Route path="/article/:id" component={Article} />
<Route path="/article/:id/recommend" component={ArticleRecommend} />
</Switch>
複製程式碼
寫成一排,業務如下
path | 元件 | 說明 |
---|---|---|
/article | ArticleList | 文章列表 |
/article/:id | Article | 文章 |
/article/:id/recommend | ArticleRecommend | 文章推薦 |
6. 自定義路由
適合用來做許可權檢查
6.1 建立自定義 Route
const isAuthenticated = true
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
複製程式碼
6.2 使用自定義路由
...
<Route path="/public" component={Public} />
<Route path="/login" component={Login} />
<PrivateRoute path="/protected" component={Protected} />
複製程式碼
7. 轉換動畫
這裡用到了 react-transition-group
庫
動圖效果
7.1 安裝
yarn add react-transition-group
複製程式碼
7.2 編寫動畫 css
檔案 fade.css
.fade-enter {
opacity: 0;
z-index: 1;
}
.fade-enter-active {
opacity: 1;
transition: opacity 250ms ease-in;
}
.fade-exit {
opacity: 0;
}
複製程式碼
名稱 | 說明 |
---|---|
fade-enter | 動畫啟動 |
fade-enter-active | 動畫啟用 |
fade-exit | 動畫離開 |
其它動畫樣式名字可以參考 css-transition
7.3 匯入包和動畫樣式
...
import {TransitionGroup, CSSTransition} from `react-transition-group`
import `./fade.css`
複製程式碼
TransitionGroup, CSSTransition
必須匯入
7.4 編寫樣式
const styles = {}
styles.fill = {
position: `relative`,
height: `200px`,
width: `500px`
}
styles.content = {
...styles.fill,
top: `40px`,
textAlign: `center`,
height: `120px`
}
styles.nav = {
padding: 0,
margin: 0,
position: `absolute`,
top: 0,
height: `40px`,
width: `100%`,
display: `flex`
}
styles.navItem = {
textAlign: `center`,
flex: 1,
listStyleType: `none`,
padding: `10px`
}
styles.hsl = {
color: `white`,
paddingTop: `20px`,
fontSize: `30px`,
height: `120px`
}
styles.rgb = {
color: `white`,
paddingTop: `20px`,
fontSize: `30px`,
height: `120px`
}
複製程式碼
這是 react
的樣式物件,當然你也可以寫成 .css
檔案
7.5 編寫導航
const NavLink = props => (
<li style={styles.navItem}>
<Link {...props} style={{color: `inherit`}} />
</li>
)
複製程式碼
7.6 編寫展示元件
// 切換區域 A
const HSL = ({match: {params}}) => (
<div
style={{
...styles.fill,
...styles.hsl,
background: `hsl(${params.h}, ${params.s}%, ${params.l}%)`
}}
>
hsl({params.h}, {params.s}%, {params.l}%)
</div>
)
// 切換區域 B
const RGB = ({match: {params}}) => (
<div
style={{
...styles.fill,
...styles.rgb,
background: `rgb(${params.r}, ${params.g}, ${params.b})`
}}
>
rgb({params.r}, {params.g}, {params.b})
</div>
)
複製程式碼
7.7 編寫容器元件
const RouterView = () => (
<Router>
<Route
render={({location}) => (
<div style={styles.fill}>
<Route
exact
path="/"
render={() => <Redirect to="/hsl/10/90/50" />}
/>
<ul style={styles.nav}>
<NavLink to="/hsl/10/90/50">Red</NavLink>
<NavLink to="/hsl/120/100/40">Green</NavLink>
<NavLink to="/rgb/33/150/243">Blue</NavLink>
<NavLink to="/rgb/240/98/146">Pink</NavLink>
</ul>
<div style={styles.content}>
<TransitionGroup>
<CSSTransition key={location.key} classNames="fade" timeout={300}>
<Switch location={location}>
<Route exact path="/hsl/:h/:s/:l" component={HSL} />
<Route exact path="/rgb/:r/:g/:b" component={RGB} />
<Route render={() => <div>Not Found</div>} />
</Switch>
</CSSTransition>
</TransitionGroup>
</div>
</div>
)}
/>
</Router>
)
複製程式碼
- codepen
程式碼
- reactjs-example / 5-1-routerBase
- reactjs-example / 5-2-routerParams
- reactjs-example / 5-3-routerNoMatch
- reactjs-example / 5-4-routerTransitions
- reactjs-example / 5-5-routerRedirect