在react中,一般都是使用单页面应用(SPA),即整个页面只有一个html,而后经过不一样的url地址进行组件的匹配和切换。html
咱们看到的url地址可能会有两种形式,一种是 localhost:3000/home,一种是 localhost:3000/#/home,两种地址的区别在于有无#,有#的是根据hash来进行匹配,即url中的锚点,本质上是经过location.hash来改变href,hash后的内容是不会发送给服务器的,没有#是经过html5的history来进行跳转,二者跳转后都不会进行刷新。html5
如下路由是美团和网易云音乐的,能够看到他们的路由地址的分别是基于hash和historyreact
具体来讲,经过#来区分路由的实现原理是监听hash的变化,这里监听的方式是使用hashchange 事件,当url地址发生了变化时,经过匹配当前url的地址来进行展现,代码以下所示web
<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
下面来讲说react-router的经常使用组件dom
一、<Link>和<NavLink>,这两个标签都是由a标签的封装,经过to属性指定跳转的连接地址,<NavLink>比<Link>多的是能够指定选中的样式和类名,格式如this
<Link to="/about">关于</Link>
经过<Link>标签,点击以后就能够跳转到指定的地址,此时即便外层包裹的是HashRouter,也不须要本身加上#,react-router会帮咱们在url上加上#url
二、当使用<Link>定义了跳转的url地址后,此时须要指定匹配跳转该url地址时须要显示的内容,此时使用的是<Route>,经过path属性指定url地址,component属性指定渲染的组件,格式如spa
<Route path="/about" component={About} />
加上了以后, /about这个地址显示的就是About这个组件里的内容。<Route>进行的是模糊匹配,一个url路径可能能够匹配多个Route,若是须要严格匹配的话,能够增长一个属性 exact,适合没有二级路由的时候开启。
三、在有不少的Route的状况下,即便在第一个Route匹配到合适的以后,仍然会继续向下匹配,直到最后一个,因此在全部的<Route>外包裹一个<Switch>标签可让它进行惟一的匹配,匹配到合适的以后就不继续匹配了。
四、当全部的<Route>都没法匹配到url上的地址时,能够定义 <Redirect>组件直接重定向到一个页面,经过to来指定路由地址,这个组件要放置到<Route>的最后面,由于它和<Link>不一样,<Link>是点击了以后才会跳转对应的地址,而<Redirect>会直接执行并跳转
<Redirect to="/about"/>
五、经过路由来匹配的组件称为路由组件,<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值或者两个页面之间跳转的时候传递一些参数,这时候有三种路由传参方式
一、params传参
<NavLink to="/detail/1">商品详情</NavLink> <Route path="/detail/:id" component={Detail}/> // 若是是自行定义跳转的地址能够经过 this.props.history.push("/detail/1")
此时的id就是动态的,能够在id这个位置传递任意的数值或者字符串,而后经过props里的match对象中的params获取动态匹配的内容
二、search传参
<NavLink to="/detail?id=1">商品详情</NavLink> <Route path="/detail" component={Detail}/> // 若是是自行定义跳转的地址能够经过 this.props.history.push("/detail?id=1")
此时至关于在url上添加一个问号进行拼接,须要把地址拼成一种键值对的形式,经过 props里的location对象中的search属性获取从问号开始的匹配内容,这一种路由的匹配方式须要自行解析字符串
三、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)