經過 URL 映射到對應的功能實現,React 的路由使用要先引入 react-router.js。
注意:
react-router 4.0 以上的版本和 3.0 及如下的版本有很大的差異,本教程使用的是 3.0.2 的版本,後續會更新 4.0 以上版本的教程。
在使用 npm 安裝時默認是安裝最新版本,若是安裝的版本是最新的,而使用上用的是 3.0 版本的用法,則會報錯。
因此在 npm 安裝時要指定版本 npm install react-router@3.0.2 --save-dev
。javascript
傳統的前端基本都是經過頁面之間跳轉來實現各功能模塊的切換,這種作法會致使一個項目下來存在大量的 html 頁面,並且每一個頁面都有一大堆的靜態資源文件須要引入,在性能一直被垢病。後來有了隨着 ajax 的普及,還有 jQuery 對 ajax 的封裝後的便捷使用,開發者會大量的使用 ajax 來加載一個 html 頁面到當前頁面的某個容器當中來實現無刷新加載,但依然沒有解決大量存在 html 頁面和每一個頁面加載大量的靜態資源文件而致使性能上的問題。隨着移動互聯網的普及,移動端對頁面加載的性能要求和流量的限制愈來愈高,因此主流的前端框架都往 SPA 方向靠齊。
SPA,Single Page Application 的縮寫,單頁面應用,其目的是整個應用程序只有一個 html 頁面,結合構建 webpack 的統一打包思想,把全部靜態資源文件打包成一個 js 文件,在惟一的一個 html 頁面引用,從而真正意義上實現一個 html 文件,一個 js 文件完成一個應用的構想。
SPA 優化了靜態加載的性能,但一個應用程序仍是有不少的功能模塊,功能模塊之間的切換,就變成了組件之間的切換,因此到目前爲止基本上主流的前端框架都會有路由和組件兩個概念,並且實現思想都是一致的。html
//es5 var {Router, Route, hashHistory, Link, IndexRoute, browserHistory} = require("react-router"); //es6 import {Router, Route, hashHistory, Link, IndexRoute, browserHistory} from 'react-router'; //es5 和 es6 的使用都是同樣的 <Link to="/">Root</Link> <Router> <Route path='/' component={RootComponent}/> </Router> //使用 `<script>` 標籤 <script src="../js/ReactRouter.js"></script> <ReactRouter.Link to="/">Root</ReactRouter.Link> <ReactRouter.Router> <ReactRouter.Route path='/' component={RootComponent}/> </ReactRouter.Router>
a
標籤。to
等同於 a
標籤的 href
。<Link to="/page">page</Link>
,做用等同於 <a href="#/page">page</a>
。屬性 history
有兩個屬性值:前端
hashHistory
路由將經過URL的hash部分(#)切換,推薦使用。<Router history={hashHistory}>
對應的 URL 形式相似 example.com/#/some/pathbrowserHistory
這種狀況須要對服務器改造。不然用戶直接向服務器請求某個子路由,會顯示網頁找不到的404錯誤。<Router history={browserHistory}>
對應的 URL 形式相似 example.com/some/path。Route
是組件 Router
子組件,能夠經過嵌套 route
來實現路由嵌套。path
:指定路由的匹配規則,這個屬性是能夠省略的,這樣的話,無論路徑是否匹配,老是會加載指定組件。component
:指當 URL 映射到路由的匹配規則時會渲染對應的組件。<Route path="/" component={RootComponent}/>
當 URL 爲 example.com/#/ 時會渲染組件 RootComponent<Route path="/page1" component={Page1Component}/>
當 URL 爲 example.com/#/page1 時會渲染組件 Page1Componentimport React from 'react' import ReactDOM from 'react-dom' import {Router, hashHistory, browserHistory} from 'react-router' const html = ( <ul> <li><Link to="/">Root</Link></li> <li><Link to="/page">page</Link></li> </ul> ) class RootComponent extends React.Component{ render(){ return ( <div> <h1>RootComponent</h1> {html} </div> ) } } class PageComponent extends React.Component{ render(){ return ( <div> <h1>PageComponent</h1> {html} </div> ) } } ReactDOM.render( <Router history={hashHistory}> <Route path='/' component={RootComponent}/> <Route path='/page' component={PageComponent}/> </Router>, document.getElementById('app') )
效果預覽java
this.props.params.paramName
來獲取。:paramName
node
<Route path="/user/:name">
。this.props.params.name
的值爲 sam。import React from 'react' import ReactDOM from 'react-dom' import {Router, hashHistory, browserHistory} from 'react-router' class UserComponent extends React.Component{ render(){ return ( <div> <h3>UserComponent 單個參數 </h3> <p>路由規則:path='/user/:username'</p> <p>URL 映射:{this.props.location.pathname}</p> <p>username:{this.props.params.username}</p> </div> ) } } ReactDOM.render( <Router history={hashHistory}> <Route path='/user/:username' component={UserComponent}/> </Router>, document.getElementById('app') )
(:paramName)
react
<Route path="/order(/:orderid)">
。this.props.params.orderid
獲取的值爲 undefined。this.props.params.orderid
獲取參數的值爲 001。import React from 'react' import ReactDOM from 'react-dom' import {Router, hashHistory, browserHistory} from 'react-router' class UserComponent extends React.Component{ render(){ return ( <div> <h3>OrderComponent 可選參數 </h3> <p>路由規則:path='/order(/:orderid)'</p> <p>URL 映射:{this.props.location.pathname}</p> <p>orderid:{this.props.params.orderid}</p> </div> ) } } ReactDOM.render( <Router history={hashHistory}> <ReactRouter.Route path='/order(/:orderid)' component={UserComponent}/> </Router>, document.getElementById('app') )
*.*
webpack
<Route path="/all1/*.*">
。this.props.params
獲取的參數爲一個固定的對象: {splat: [*, *]}
。{splat: ['001', 'jpg']}
。{splat: ['001', 'html']}
。*
git
<Route path="/all2/*">
。this.props.params
獲取的參數爲一個固定的對象: {splat: '*'}
。{splat: ''}
。{splat: 'a'}
。{splat: 'a/b'}
。**
es6
<Route path="/**/*.jpg">
this.props.params
獲取的參數爲一個固定的對象: {splat: [**, *]}
。{splat: ['a', '001']}
。{splat: ['a/b', '001']}
。效果預覽github
當訪問一個嵌套路由時,指定默認顯示的組件
import React from 'react' export default class AppComponent extends React.Component{ render(){ return <div>{this.props.children}</div> } }
import React, {Component} from 'react' export default class LoginComponent extends Component{ login(){} render(){ return <h1>Login</h1> } }
import React, {Component} from 'react' export default class HomeComponent extends Component{ login(){} render(){ return <h1>Home</h1> } }
import React from 'react' import {Route, IndexRoute} from 'react-router' import AppComponent from '../components/app/app' import HomeComponent from '../components/home/home' import LoginComponent from '../components/login/login' const routes = ( <Route path="/" component={AppComponent}> <IndexRoute component={HomeComponent} /> <Route path="login" component={LoginComponent} /> <Route path="home" component={HomeComponent} /> </Route> ) export default routes;
IndexRoute
,則在訪問 http://localhost/#/
時頁面是空白的http://localhost/#/login
纔會顯示內容IndexRoute
,在訪問http://localhost/#/
時會默認渲染HomeComponent
可利用組件Router
的屬性routes
來實現組件模塊化
import React from 'react' import ReactDOM from 'react-dom' import {Route, Router, IndexRoute, hashHistory} from 'react-router' import AppComponent from '../components/app/app' import HomeComponent from '../components/home/home' import LoginComponent from '../components/login/login' const routes = ( <Route path="/" component={AppComponent}> <IndexRoute component={HomeComponent} /> <Route path="login" component={LoginComponent} /> <Route path="home" component={HomeComponent} /> </Route> ) ReactDOM.render( <Router history={hashHistory} routes={routes} />, document.getElementById('app') )
this.props.router.push('/home/cnode')
this.props.router.push({pathname: '/home/cnode', query: {name: 'tom'}})
每一個路由都有enter
和leave
兩個鉤子函數,分別表明用戶進入時和離開時觸發。
進入路由/home
前會先觸發onEnter
方法,若是已登陸,則直接next()
正常進入目標路由,不然就先修改目標路徑replace({ pathname: 'login' })
,再next()
跳轉。
let isLogin = (nextState, replace, next) => { if(window.localStorage.getItem('auth') == 'admin'){ next() } else { replace({ pathname: 'login' }) next(); } } const routes = ( <Route path="/" component={AppComponent}> <Route path="login" component={LoginComponent} /> <Route path="home" component={HomeComponent} onEnter={isLogin}/> </Route> )
對應的setRouteLeaveHook
方法,若是return true
則正常離開,不然則仍是停留在原路由
import React from 'react' import {Link} from 'react-router' export default class Component1 extends React.Component{ componentDidMount(){ this.props.router.setRouteLeaveHook( this.props.route, this.routerWillLeave ) } routerWillLeave(){ return '確認要離開?' } render(){ return ( <div> <Link to="/login">Login</Ling> </div> ) } }