npm install -S react-router
使用時,路由器Router就是React的一個組件,Router組件自己只是個容器,真正的路由要經過Route組件定義html
import React from 'react'; import ReactDOM from 'react-dom'; import {Router,Route,hashHistory} from 'react-router'; import App from './App.jsx'; import About from './About.jsx'; ReactDOM.render( <Router history={hashHistory}> <Route path="/" component={App}/> <Route path="/about" component={About}/> </Router> , document.getElementById('app'))
Router組件的history屬性,用來監聽瀏覽器地址欄的變化,並將URL解析成一個地址對象,供React Router匹配,history一個能夠設置三個值react
若是設爲browserHistory
,瀏覽器顯示的路徑是 example.com/some/path,背後調用的是瀏覽器的Histtory API.webpack
注意:使用
browserHistory
時須要對服務器改造,不然用戶直接向服務器請求某個子路由,會顯示找不到網頁404錯誤,若是開發服務器是webpack-dev-server 加上--history-api-fallback參數就能夠了,以下在package.json中,其餘服務器的配置請參考 https://github.com/ReactTraining/react-router/blob/master/docs/guides/Histories.md#configuring-your-servergit
"scripts": { "dev": "webpack-dev-server --history-api-fallback --hot", "build": "webpack --progress --hide-modules" },
若是設爲hashHistory
,路由將經過URL的hash部分#
切換,URL的形式相似 example.com/#/some/path
github
createMemoryHistory
主要用於服務器渲染,它建立一個內存中的history對象,不與瀏覽器URL互動。web
const history = createMemoryHistory(location)
Route組件還能夠嵌套npm
ReactDOM.render( <Router history={browserHistory}> <Route path="/" component={Layout}> <Route path="/index" component={App}/> <Route path="/about" component={About}/> </Route> </Router> , document.getElementById('app'))
上面代碼中,用戶訪問/index或/about時候會先加載Layout組件,而後在Layout組件內部加載App或Abot,爲此Layout組件須要加個 {this.props.children}json
import React from "react" export default React.createClass({ render(){ return ( <div> <ul> <li><Link to="index">Index</Link></li> <li><Link to="about">About</Link></li> </ul> {this.props.children} </div> ) } })
上面代碼中,{this.props.children} 表明子組件 子路由也能夠不寫在Router組件裏面,單獨傳入Router組件的routers屬性api
import React from 'react'; import ReactDOM from 'react-dom'; import {Router,Route,hashHistory,browserHistory,createMemoryHistory} from 'react-router'; import Layout from './Layout.jsx'; import App from './App.jsx'; import About from './About.jsx'; let routes = <Route component={Layout}> <Route path="/" component={App} /> <Route path="/about" component={About} /> </Route> ReactDOM.render( <Router routes={routes} history={browserHistory}></Router> , document.getElementById('app'))
Route組件的path屬性指定路由的匹配規則,這個屬性是能夠省略,這樣的話,無論路徑是否匹配,老是會加載指定組件。瀏覽器
<Route path="home" component={Layout}> <Route path="index" component={App} /> <Route path="about(/:name)" component={About} /> </Route>
上面的例子中當用戶訪問/home/about/map 的時候,會加載下面的組件
<Layout> <About /> </Layout>
若是省略外層Route的path參數,寫成下面的樣子
<Route component={Layout}> <Route path="index" component={App} /> <Route path="about/:name" component={About} /> </Route>
如今訪問/about/test的時候會加載下面的組件
<Layout> <About /> </Layout>
path屬性可使用通配符
<Route path="/hello/:name"> 匹配 /hello/michael <Route path="/hello(/:name)> 匹配 /hello | /hello/test <Route path="/hello/*.*> 匹配 /hello/a.jpg <Route path="/hello/*> 匹配 /hello/ | /hello/test <Route path="/**/*.jpg> 匹配 /hello/a.jpg | /hello/path/to/a.jpg
通配符規則以下
:paramName
匹配URL的一個部分,知道遇到下一個/、?、#
爲止,這個路徑參數能夠經過this.props.params.paramName
取出()
表示URL的這個部分是可選的*
匹配任意字符,知道模式裏面的下一個字符爲止,匹配方式是非貪婪模式。**
匹配任意字符,知道下一個 /、?、#
爲止,匹配方式是貪婪模式。path
屬性也可使用相對路徑(不以/
開頭),匹配時就會相對於父組件的路徑,能夠參考上一節的例子。嵌套路由若是想擺脫這個規則,可使用絕對路由。 路由匹配規則是從上到下執行,一旦發現匹配,就再也不匹配其他的規則了
<Route path="/hello" component="Hello"> <Route path="/hello" component="About">
上面的代碼中,路徑/hello
同時匹配兩個規則,第二個規則不會生效。 設置路徑參數時,須要特別當心這一點。
<Route> <Route path="/:userName/:id" component="Hello"> <Route path="/about/me" component="About"> </Route>
上面的代碼中,用戶訪問 /about/me
的時候永遠不會觸發第二個路由規則,由於匹配到第一個規則時候就匹配上了,不會向下走了,所以 帶參數的路徑通常要寫在路由規則的底部。
此外,URL的查詢字符串 /foo?bar=baz
,能夠用 this.props.location.query.bar
獲取
IndexRoute組件是爲了解決默認狀況下根路由的子組件問題的
<Router history={hashHistory}> <Route path="/" component={Layout}> <IndexRoute component={Index} /> <Route path="app" component={App} /> <Route path="about(/:name)" component={About} /> </Route> </Router>
上面代碼中,訪問根路徑 /
會加載Index
組件到Layout
組件的this.props.children
注意:IndexRoute組件沒有路徑參數path
Redirect組件用於路由的跳轉,即用戶訪問一個路由,會自動跳轉到另外一個路由
<Route path="/" component={Layout}> <Redirect from="/foo" to="/404" /> <Route path="404" component={U404} /> <Route path="app" component={App} /> <Route path="about(/:name)" component={About} /> </Route>
如今訪問/foo
,就會自動跳轉到/404
。
IndexRedirect 組件用於訪問根路由的時候,講用戶重定向到某個子路由
<Route path="/" component={Layout}> <IndexRedirect to="/404" /> <Route path="404" component={U404} /> <Route path="app" component={App} /> <Route path="about(/:name)" component={About} /> </Route>
上面代碼中,用戶訪問根路徑時,將自動重定向到子路由中
Link
組件用於取代<a>
元素,生成一個連接,容許用戶點擊後跳轉到另外一個路由。它基本上就是<a>
元素的React版本,能夠接收Router的狀態。
<ul> <li><Link to="/">Index</Link></li> <li><Link to="app">App</Link></li> <li><Link to="about/ggg">About</Link></li> </ul>
若是但願當前的路由與其餘路由有不一樣樣式,這時可使用Link組件的activeStyle屬性
<li><Link to="app" activeStyle={{color:'red'}}>App</Link></li> <li><Link to="about" activeStyle={{color:'red'}}>About</Link></li>
上面代碼中,當前頁面的連接會紅色顯示。
另外一種作法是,使用activeClassName
指定當前路由的Class.
<li><Link to="app" activeClassName="active">App</Link></li> <li><Link to="about" activeClassName="active">About</Link></li>
上面代碼中,當前頁面的連接會紅色顯示。
在Router
組件以外,導航到路由頁面,可使用瀏覽器的History API,像下面這樣寫。
import { browserHistory } from 'react-router'; browserHistory.push('/some/path');
或者這樣
this.context.router.push('/some/path')
若是連接到根路由/
,不要使用Link組件,而要使用IndexLink
組件。
這是由於對於根路由來講,activeStyle
和activeClassName
會失效,或者說老是生效,由於/
會匹配任何子路由,而IndexLink
組件會使用路徑的精確匹配
<IndexLink to="/" activeStyle={{color:'red'}}>Index</IndexLink>
上面代碼中,根路由只會在精確匹配時,纔會變成紅色
另外一種方法是使用Link
組件的 onlyActiveOnIndex
屬性,也能達到一樣效果。
<Link to="/" activeStyle={{color:'red'}} onlyActiveOnIndex={true}>Index</Link>
實際上,IndexLink
就是對Link組件的onlyActiveOnIndex屬性的包裝
每一個路由都有Enter和Leave鉤子,用戶進入或離開該路由時觸發。
<Route path="/app" component={App} onEnter={beforeRouter} onLeave={afterRouter} />
上面的例子中,用戶進入/app
的時候會觸發onEnter
鉤子,用戶離開/app
的時候會觸發onLeave
鉤子,詳細例子請看下面
import React from 'react'; import ReactDOM from 'react-dom'; import {Router,Route,IndexRoute,hashHistory} from 'react-router'; import Layout from './Layout.jsx'; import App from './App.jsx'; import Index from './Index.jsx'; import About from './About.jsx'; import NotFound from './NotFound.jsx'; const beforeRouter = (nextState,replace)=>{ console.log("beforeRouter",nextState,replace) } const afterRouter = (nextState,replace)=>{ console.log("afterRouter",nextState,replace) } ReactDOM.render( <Router history={hashHistory}> <Route path="/" component={Layout}> <IndexRoute component={Index} /> <Route path="app" component={App} onEnter={beforeRouter} onLeave={afterRouter} /> <Route path="about(/:name)" component={About} /> <Route path="*" component={NotFound} /> </Route> </Router> , document.getElementById('app'))