在react中,通常都是应用单页面利用(SPA),即整个页面只有一个html,而后通过不同的url地址进行组件的匹配和切换。
咱们看到的url地址可能会有两种模式,一种是 localhost:3000/home,一种是 localhost:3000/#/home,两种地址的区别在于有无#,有#的是依据hash来进行匹配,即url中的锚点,实质上是通过location.hash来扭转href,hash后的内容是不会发送给服务器的,没有#是通过html5的history来进行跳转,两者跳转后都不会进行刷新。
以下路由是美团和网易云音乐的,能够看到他们的路由地址的别离是基于hash和history
具体来说,通过#来辨别路由的实现原理是监听hash的变动,这里监听的形式是应用hashchange 事件,当url地址产生了变动时,通过匹配以后url的地址来进行展现,代码如下所示
<body> <div> <a href="#/home">首页</a> <a href="#/about">对于</a> </div> <div id="content"></div> <script> window.addEventListener('hashchange',()=>{ const content = document.getElementById('content') switch(location.hash){ case '#/home': content.innerHTML = '首页' break case '#/about': content.innerHTML = '对于' break default: content.innerHTML = '' } }) </script></body>
通过html5的history来实现跳转无刷新,就须要阻止a标签的默认行为,再通过history的pushState这一办法实现url地址的替换,同样是监听url地址的变动,这里应用popState办法,当url地址产生了变动之后,展现对应的内容。
<body> <div> <div> <a href="/home">首页</a> <a href="/about">对于</a> </div> <div id="content"> </div></body><script> const content = document.getElementById('content') const aEles = document.getElementsByTagName('a') for (let el of aEles) { el.addEventListener('click', (event) => { event.preventDefault() const href = el.getAttribute("href") history.pushState({}, '', href) urlchange() }) } window.addEventListener('popstate', () => { urlchange() }) function urlchange() { switch (location.pathname) { case '/home': content.innerHTML = '首页' break case '/about': content.innerHTML = '对于' break default: content.innerHTML = '' } }</script>
以上的锚点和history别离对应了react-router中的HashRouter和BrowserRouter,在react-router中,想要应用路由组件必须在最外层包裹一层HashRouter或者BrowserRouter,来抉择想要应用的路由类型,而后能力应用react-router提供的其它组件,react-route中用于web端的库为react-router-dom,以下所有的组件都是从react-router-dom中导出。
上面来说说react-router的罕用组件
1、<Link>和<NavLink>,这两个标签都是由a标签的封装,通过to属性指定跳转的链接地址,<NavLink>比<Link>多的是能够指定选中的款式和类名,格局如
<Link to="/about">对于</Link>
通过<Link>标签,点击之后就能够跳转到指定的地址,此时即便外层包裹的是HashRouter,也不须要本人加上#,react-router会帮咱们在url上加上#
2、当应用<Link>定义了跳转的url地址后,此时须要指定匹配跳转该url地址时须要显示的内容,此时应用的是<Route>,通过path属性指定url地址,component属性指定渲染的组件,格局如
<Route path="/about" component={About} />
加上了之后, /about这个地址显示的就是About这个组件里的内容。<Route>进行的是含糊匹配,一个url门路可能能够匹配多个Route,如果须要严格匹配的话,能够减少一个属性 exact,适宜没有二级路由的时候开启。
3、在有很多的Route的状况下,即便在第一个Route匹配到适合的之后,依然会持续向下匹配,直到最初一个,所以在所有的<Route>外包裹一个<Switch>标签能够让它进行惟一的匹配,匹配到适合的之后就不持续匹配了。
4、当所有的<Route>都无奈匹配到url上的地址时,能够定义 <Redirect>组件间接重定向到一个页面,通过to来指定路由地址,这个组件要搁置到<Route>的最初面,因为它和<Link>不同,<Link>是点击了之后才会跳转对应的地址,而<Redirect>会间接执行并跳转
<Redirect to="/about"/>
5、通过路由来匹配的组件称为路由组件,<Route path="/about" component={About} />,这里的About就是路由组件,和其它的组件是不一样的,路由组件的props里有一些数据,其中包含三大属性,history、location和match,history能够自定义页面的跳转,location用来获取url地址相干的信息,match能够用作动静路由的匹配。
但个别的组件是没有这些props属性的,如果个别的组件也须要这样一些属性的话,能够通过一个高阶组件 withRouter。如
class myCom extends PureComponent { }export default withRouter(myCom)
再来说说路由传参
有时候,咱们心愿在链接上带一个id值或者两个页面之间跳转的时候传递一些参数,这时候有三种路由传参形式
1、params传参
<NavLink to="/detail/1">商品详情</NavLink><Route path="/detail/:id" component={Detail}/>// 如果是自行定义跳转的地址能够通过 this.props.history.push("/detail/1")
此时的id就是动静的,能够在id这个地位传递任意的数值或者字符串,而后通过props里的match对象中的params获取动静匹配的内容
2、search传参
<NavLink to="/detail?id=1">商品详情</NavLink><Route path="/detail" component={Detail}/>// 如果是自行定义跳转的地址能够通过 this.props.history.push("/detail?id=1")
此时相当于在url上增加一个问号进行拼接,须要把地址拼成一种键值对的模式,通过 props里的location对象中的search属性获取从问号开始的匹配内容,这一种路由的匹配形式须要自行解析字符串
3、state传参
<NavLink to={ pathname: "/detail", state: { id: 1} }>商品详情</NavLink><Route path="/detail" component={Detail}/>// 如果是自行定义跳转的地址能够通过 this.props.history.push("/detail", { id: 1})
这样的传递参数形式通过props里的location对象中的state属性来获取传递的值,这种形式的能够间接以对象的模式传递,并且可传递的数据更多,这些参数不会显示在url上
用一个小的组合案例展现以上内容
import React, { PureComponent } from 'react'import { NavLink, Route, Switch, withRouter, Redirect } from "react-router-dom"import Home from "./pages/Home"import About from "./pages/About"import Detail from "./pages/Detail"import Product from './pages/Product'class App extends PureComponent { jumpToProduct(){ this.props.history.push('/product') } render() { return ( <div> <NavLink exact to="/">首页</NavLink> <NavLink to="/about">对于</NavLink> <NavLink to="/detail/1">详情</NavLink> <button onClick={e=>this.jumpToProduct()}>商品</button> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/detail/:id" component={Detail} /> <Route path="/product" component={Product}/> <Redirect to="/"/> </Switch> </div> ); }}export default withRouter(App)