React项目的可用的路由库是React-Router
,固然这也是官方支持的。它也分为:javascript
如下教程咱们都以Web端为主,因此全部的教程内容都是默认关于
react-router-dom
的介绍。php
进行网站(将会运行在浏览器环境中)构建,咱们应当安装react-router-dom
。react-router-dom
暴露出react-router
中暴露的对象与方法,所以你只须要安装并引用react-router-dom
便可。css
安装:html
yarn add react-router-dom
# 或者,不使用 yarn npm install react-router-dom
如今的React Router版本中已不须要路由配置,如今一切皆组件。java
ReactRouter中提供了如下三大组件:node
固然每一个组件下又会有几种不一样的子类组件实现。好比: Router组件就针对不一样功能和平台对应用:react
<BrowserRouter>
浏览器的路由组件<HashRouter>
URL格式为Hash路由组件<MemoryRouter>
内存路由组件<NativeRouter>
Native的路由组件<StaticRouter>
地址不改变的静态路由组件三大组件使用的关系:git
若是说咱们的应用程序是一座小城的话,那么Route就是一座座带有门牌号的建筑物,而Link就表明了到某个建筑物的路线。有了路线和目的地,那么就缺一位老司机了,没错Router就是这个老司机。github
如今你能够复制任意的示例代码,并粘贴到 src/App.js
。以下:web
import React, { Component } from 'react'; import { HashRouter as Router, Link, Route } from 'react-router-dom'; import './App.css'; const Home = () => ( <div> <h2>Home</h2> </div> ) const About = () => ( <div> <h2>About</h2> </div> ) const Product = () => ( <div> <h2>Product</h2> </div> ) class App extends Component { render() { return ( <Router> <div className="App"> <Link to="/">Home</Link> <Link to="/About">About</Link> <Link to="/Product">Product</Link> <hr/> <Route path="/" exact component={Home}></Route> <Route path="/about" component={About}></Route> <Route path="/product" component={Product}></Route> </div> </Router> ); } } export default App;
BrowserRouter
主要使用在浏览器中,也就是WEB应用中。它利用HTML5 的history API来同步URL和UI的变化。当咱们点击了程序中的一个连接以后,BrowserRouter
就会找出与这个URL
匹配的Route
,并将他们对应的组件渲染出来。 BrowserRouter
是用来管理咱们的组件的,那么它固然要被放在最顶级的位置,而咱们的应用程序的组件就做为它的一个子组件而存在。
import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; ReactDOM.render( <BrowserRouter> <App/> </BrowserRouter>, document.body);
BrowserRouter
组件提供了四个属性。
basename
: 字符串类型,路由器的默认根路径forceRefresh
: 布尔类型,在导航的过程当中整个页面是否刷新getUserConfirmation
: 函数类型,当导航须要确认时执行的函数。默认是:window.confirm
keyLength
: 数字类型location.key
的长度。默认是 6当前位置的基准 URL。若是你的页面部署在服务器的二级(子)目录,你须要将 basename
设置到此子目录。正确的 URL 格式是前面有一个前导斜杠,但不能有尾部斜杠。
例如:有时候咱们的应用只是整个系统中的一个模块,应用中的URL老是以 http://localhost/admin/ 开头。这种状况下咱们总不能每次定义Link和Route的时候都带上admin吧?react-router已经考虑到了这种状况,因此为咱们提供了一个basename属性。为BrowserRouter设置了basename以后,Link中就能够省略掉admin了,而最后渲染出来的URL又会自动带上admin。
<BrowserRouter basename="/admin"/> ... <Link to="/home"/> // 被渲染为 <a href="/admin/home"> ... </BrowserRouter>
当导航须要确认时执行的函数。默认使用 window.confirm
。
// 使用默认的确认函数 const getConfirmation = (message, callback) => { const allowTransition = window.confirm(message) callback(allowTransition) } <BrowserRouter getUserConfirmation={getConfirmation}/>
当设置为 true
时,在导航的过程当中整个页面将会刷新。 只有当浏览器不支持 HTML5 的 history API 时,才设置为 true
。
const supportsHistory = 'pushState' in window.history <BrowserRouter forceRefresh={!supportsHistory}/>
location.key
的长度。默认是 6。
<BrowserRouter keyLength={12}/>
渲染单一子组件(元素)。
HashRouter
使用 URL 的 hash (例如:window.location.hash
) 来保持 UI 和 URL 的同步。
注意: 使用 hash 的方式记录导航历史不支持
location.key
和location.state
。在之前的版本中,咱们为这种行为提供了 shim,可是仍有一些问题咱们没法解。任何依赖此行为的代码或插件都将没法正常使用。因为该技术仅用于支持传统的浏览器,所以在用于浏览器时可使用<BrowserHistory>
代替。
跟BrowserRouter
相似,它也有:basename
、getUserConfirmation
、children
属性,并且是同样的。
window.location.hash
使用的 hash 类型。有以下几种:
"slash"
- 后面跟一个斜杠,例如 #/
和 #/sunshine/lollipops
"noslash"
- 后面没有斜杠,例如 #
和 #sunshine/lollipops
"hashbang"
- Google 风格的 "ajax crawlable",例如 #!/
和 #!/sunshine/lollipops
默认为 "slash"
。
主要用在ReactNative这种非浏览器的环境中,所以直接将URL的history保存在了内存中。 StaticRouter 主要用于服务端渲染。
Link就像是一个个的路牌,为咱们指明组件的位置。Link使用声明式的方式为应用程序提供导航功能,定义的Link最终会被渲染成一个a标签。Link使用to这个属性来指明目标组件的路径,能够直接使用一个字符串,也能够传入一个对象。
import { Link } from 'react-router-dom' // 字符串参数 <Link to="/query">查询</Link> // 对象参数 <Link to={{ pathname: '/query', search: '?key=name', hash: '#hash', state: { fromDashboard: true } }}>查询</Link>
须要跳转到的路径(pathname)或地址(location)。
当设置为 true
时,点击连接后将使用新地址替换掉访问历史记录里面的原地址。
当设置为 false
时,点击连接后将在原有访问历史记录的基础上添加一个新的纪录。
默认为 false
。
<Link to="/courses" replace />
NavLink是一个特殊版本的Link,可使用activeClassName来设置Link被选中时被附加的class,使用activeStyle来配置被选中时应用的样式。此外,还有一个exact属性,此属性要求location彻底匹配才会附加class和style。这里说的匹配是指地址栏中的URl和这个Link的to指定的location相匹配。
// 选中后被添加class selected
<NavLink to={'/'} exact activeClassName='selected'>Home</NavLink> // 选中后被附加样式 color:red <NavLink to={'/gallery'} activeStyle={{color:red}}>Gallery</NavLink>
activeClassName
默认值为active
true
时,在肯定位置是否与当前 URL 匹配时,将考虑位置 pathname
后的斜线。Route应该是react-route中最重要的组件了,它的做用是当location与Route的path匹配时渲染Route中的Component。若是有多个Route匹配,那么这些Route的Component都会被渲染。
与Link相似,Route也有一个exact属性,做用也是要求location与Route的path绝对匹配。
// 当location形如 http://location/时,Home就会被渲染。 // 由于 "/" 会匹配全部的URL,因此这里设置一个exact来强制绝对匹配。 <Route exact path="/" component={Home}/> <Route path="/about" component={About}/>
<Route path="/home" render={() => { console.log('额外的逻辑'); return (<div>Home</div>); }/>
1、它同render相似,是一个function。不一样的地方在于它会被传入一个match参数来告诉你这个Route的path和location匹配上没有。
2、第二个特殊的地方在于,即便path没有匹配上,咱们也能够将它渲染出来。秘诀就在于前面一点提到的match参数。咱们能够根据这个参数来决定在匹配的时候渲染什么,不匹配的时候又渲染什么。
// 在匹配时,容器的calss是light,<Home />会被渲染 // 在不匹配时,容器的calss是dark,<About />会被渲染 <Route path='/home' children={({ match }) => ( <div className={match ? 'light' : 'dark'}> {match ? <Home/>:<About>} </div> )}/>
全部路由中指定的组件将被传入如下三个 props 。
这里主要说下match.params.透过这个属性,咱们能够拿到从location中解析出来的参数。固然,若是想要接收参数,咱们的Route的path也要使用特殊的写法。
以下示例,三个Link是一个文章列表中三个连接,分别指向三篇id不一样的文章。而Route用于渲染文章详情页。注意path='/p/:id' ,location中的对应的段会被解析为id=1 这样的键值。最终这个键值会做为param的键值存在。Route中的组件可使用this.props.match.params.id来获取,示例中使用告终构赋值。
<Link to='/p/1' /> <Link to='/p/2' /> <Link to='/p/3' /> ...... <Route path='/p/:id' render={(match)=<h3>当前文章ID:{match.params.id}</h3>)} />
Location 是指你当前的位置,下一步打算去的位置,或是你以前所在的位置,形式大概就像这样:
{
key: 'ac3df4', // 在使用 hashHistory 时,没有 key pathname: '/somewhere' search: '?some=search-string', hash: '#howdy', state: { [userDefined]: true } }
你使用如下几种方式来获取 location 对象:
this.props.location
的方式获取,({ location }) => ()
的方式获取,({ location }) => ()
的方式获取,this.props.location
的方式获取。你也能够在 history.location
中获取 location 对象,可是别那么写,由于 history 是可变的。更多信息请参见 history 文档。
location 对象不会发生改变,所以你能够在生命周期的钩子函数中使用 location 对象来查看当前页面的位置是否发生改变,这种技巧在获取远程数据以及使用动画时很是有用。
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) { // 已经跳转了! } }
一般状况下,你只须要给一个字符串当作 location ,可是,当你须要添加一些 location 的状态时,你能够对象的形式使用 location 。而且当你须要多个 UI ,而这些 UI 取决于历史时,例如弹出框(modal),使用location 对象会有很大帮助。
// 一般你只须要这样使用 location <Link to="/somewhere"/> // 可是你一样能够这么用 const location = { pathname: '/somewhere' state: { fromDashboard: true } } <Link to={location}/> <Redirect to={location}/> history.push(location) history.replace(location)
最后,你能够把 location 传入一下组件:
这样作可让组件不使用路由状态(router state)中的真实 location,由于咱们有时候须要组件去渲染一个其余的 location 而不是自己所处的真实 location,好比使用动画或是等待跳转时。
本文档中的「history」以及「history
对象」请参照 history
包中的内容。 History 是 React Router 的两大重要依赖之一(除去 React 自己),在不一样的 Javascript 环境中,history
以多种形式实现了对于 session 历史的管理。
咱们会常用如下术语:
history
对象一般会具备如下属性和方法:
length
-( number 类型)指的是 history 堆栈的数量。action
-( string 类型)指的是当前的动做(action),例如 PUSH
,REPLACE
以及 POP
。location
-( object类型)是指当前的位置(location),location 会具备以下属性:
pathname
-( string 类型)URL路径。search
-( string 类型)URL中的查询字符串(query string)。hash
-( string 类型)URL的 hash 分段。state
-( string 类型)是指 location 中的状态,例如在 push(path, state)
时,state会描述何时 location 被放置到堆栈中等信息。这个 state 只会出如今 browser history 和 memory history 的环境里。push(path, [state])
-( function 类型)在 hisotry 堆栈顶加入一个新的条目。replace(path, [state])
-( function 类型)替换在 history 堆栈中的当前条目。go(n)
-( function 类型)将 history 对战中的指针向前移动 n
。goBack()
-( function 类型)等同于 go(-1)
。goForward()
-( function 类型)等同于 go(1)
。block(prompt)
-( function 类型)阻止跳转,(请参照 history 文档)match
对象包含了 <Route path>
如何与URL匹配的信息。match
对象包含如下属性:
params
-( object 类型)即路径参数,经过解析URL中动态的部分得到的键值对。isExact
- 当为 true
时,整个URL都须要匹配。path
-( string 类型)用来作匹配的路径格式。在须要嵌套 <Route>
的时候用到。url
-( string 类型)URL匹配的部分,在须要嵌套 <Link>
的时候会用到。你能够在如下地方获取 match
对象:
this.props.match
方式。({ match }) => ()
方式。({ match }) => ()
方式当这个组件被渲染是,location会被重写为Redirect的to指定的新location。它的一个用途是登陆重定向,好比在用户点了登陆并验证经过以后,将页面跳转到我的主页。
<Redirect to="/new"/>
渲染匹配地址(location)的第一个 <Route>
或者<Redirect>
这与只使用一堆<Route>
有什么不一样?
<Switch>
的独特之处是独它仅仅渲染一个路由。相反地,每个包含匹配地址(location)的<Route>
都会被渲染。思考下面的代码:
<Route path="/about" component={About}/> <Route path="/:user" component={User}/> <Route component={NoMatch}/>
若是如今的URL是 /about
,那么 <About>
, <User>
, 还有 <NoMatch>
都会被渲染,由于它们都与路径(path)匹配。这种设计,容许咱们以多种方式将多个 <Route>
组合到咱们的应用程序中,例如侧栏(sidebars),面包屑(breadcrumbs),bootstrap tabs等等。 然而,偶尔咱们只想选择一个<Route>
来渲染。若是咱们如今处于 /about
,咱们也不但愿匹配 /:user
(或者显示咱们的 "404" 页面 )。如下是使用 Switch
的方法来实现:
import { Switch, Route } from 'react-router'
<Switch> <Route exact path="/" component={Home}/> <Route path="/about" component={About}/> <Route path="/:user" component={User}/> <Route component={NoMatch}/> </Switch>
如今,若是咱们处于 /about
, <Switch>
将开始寻找匹配的 <Route>
。 <Route path="/about"/>
将被匹配, <Switch>
将中止寻找匹配并渲染<About>
。 一样,若是咱们处于 /michael
, <User>
将被渲染。
这对于过渡动画也是起做用的,由于匹配的 <Route>
在与前一个相同的位置被渲染。
<Fade>
<Switch> {/* there will only ever be one child here */} {/* 这里只会有一个子节点 */} <Route/> <Route/> </Switch> </Fade> <Fade> <Route/> <Route/> {/* there will always be two children here, one might render null though, making transitions a bit more cumbersome to work out */} {/* 这里老是有两个子节点, 一个可能会渲染为null, 使计算过渡增长了一点麻烦 */} </Fade>