官方文档

一、前端路由的两种实现方案

  1. hash : hash原本的作用是为一个很长的文档页添加锚点信息,它自带不改变url刷新页面的功能,所以自然而然被用单页面应用程序中了。
  2. history : 应该说history是主流的解决方案,浏览器的前进后退用的就是这个,它是window对象下的,以前的history提供的方法只能做页面之间的前进后退,如下:
    1. history.go(number|URL) 可加载历史列表中的某个具体的页面
    2. history.forward() 可加载历史列表中的下一个 URL
    3. history.back() 可加载历史列表中的前一个 URL

为了在不刷新浏览器的情况下,创建新的浏览记录并插入浏览记录队列中,html5新增了如下方法:

  1. history.pushState(state, title, url)
    • 添加一条历史记录, state用于传递参数,可以为空。title是设置历史记录的标题,可以为空。url是历史记录的URL,不可以为空。
  2. history.replaceState(state, title, url)
    • 将history堆栈中当前的记录替换成这里的url,参数同上。
    • 这个特性后来用到了单页面应用中比如:vue-router,react-router-dom里面。


二、React中的路由

<Router>是React中实现路由最外层的容器,一般情况下我们不再需要直接使用它,而是使用在它基础之上封装的几个适用于不同环境的组件,react-router-dom的Router有四种:

Router 适用情况
BrowserRouter react-router-dom扩展,利用HTML5 新增的history API (pushState, replaceState),是web应用最常用的路由组件
HashRouter react-router-dom扩展,利用window.location.hash,适用于低版本浏览器或者一些特殊情境
MemoryRouter 继承自react-router ,用户在地址栏看不到任何路径变化,一般用在测试或者非浏览器环境开发中

StaticRouter | 继承自react-router,某些页面从渲染出来以后没有多的交互,所以没有状态的变化需要存储,就可以使用静态路由,静态路由适用于服务器端 |

一般我们很少会用到MemoryRouter和StaticRouter,在web应用中更多的是用 react-router-dom扩展出来的BrowserRouter和HashRouter,这两个就是我前面提到的前端路由的两种解决办法的各自实现。

三、HashRouter的基本使用

1. main.js

  1. npm install react-router-dom -S
  2. // 1. 导入包
  3. import React from 'react'
  4. import ReactDOM from 'react-dom'
  5. import App from './App.jsx'
  6. // 使用 render 函数渲染 虚拟DOM
  7. ReactDOM.render(<App></App>, document.getElementById('app'))

2. App.jsx

  • HashRouter 表示一个路由的跟容器,所有的路由相关的东西,都要包裹在 HashRouter 里面
  • Route 表示一个路由规则, 在 Route 上有两个比较重要的属性:path component
  • Link 表示一个路由的链接 ,就好比 vue 中的 ```javascript import React from ‘react’

import { HashRouter, Route, Link } from ‘react-router-dom’

import Home from ‘./components/Home.jsx’ import Movie from ‘./components/Movie.jsx’ import About from ‘./components/About.jsx’

export default class App extends React.Component { constructor(props) { super(props) this.state = {} }

render() { // 当 使用 HashRouter 把 App 根组件的元素包裹起来之后,网站就已经启用路由了 // 在一个 HashRouter 中,只能有唯一的一个根元素 // 在一个网站中,只需要使用 唯一的一次 就行了 return

这是网站的APP根组件

  1. <Link to="/home">首页</Link>&nbsp;&nbsp;
  2. <Link to="/movie/top250/10">电影</Link>&nbsp;&nbsp;
  3. <Link to="/about">关于</Link>
  4. <hr />
  5. {/* Route 创建的标签,就是路由规则,其中 path 表示要匹配的路由,component 表示要展示的组件 */}
  6. {/* 在 vue 中有个 router-view 的路由标签专门用来放置匹配到的路由组件的,但是在 react-router 中并没有类似于这样的标签,而是直接把 Route 标签当作的坑(占位符) */}
  7. {/* Route 具有两种身份:1. 它是一个路由匹配规则; 2. 它是一个占位符,表示将来匹配到的组件都放到这个位置, 如果想让路由规则进行精确匹配,可以为 Route添加 exact 属性,表示启用精确匹配模式 */}
  8. <Route path="/home" component={Home}></Route>
  9. <hr />
  10. {/* 注意:默认情况下,路由中的规则是模糊匹配的,如果路由可以部分匹配成功,就会展示这个路由对应的组件 */}
  11. {/* 如果要匹配参数,可以在匹配规则中使用 : 修饰符,表示这个位置匹配到的是参数 */}
  12. <Route path="/movie/:type/:id" component={Movie} exact></Route>
  13. <hr />
  14. <Route path="/about" component={About}></Route>
  15. </div>
  16. </HashRouter>

} }

  1. <a name="Kkqrx"></a>
  2. #### 3. components/Home.jsx
  3. ```javascript
  4. import React from 'react'
  5. export default class Home extends React.Component {
  6. constructor(props) {
  7. super(props)
  8. this.state = {}
  9. }
  10. render() {
  11. return <div>
  12. Home
  13. </div>
  14. }
  15. }

4. components/Movie.jsx

  1. import React from 'react'
  2. export default class Movie extends React.Component {
  3. constructor(props) {
  4. super(props)
  5. this.state = {
  6. routeParams: props.match.params
  7. }
  8. }
  9. render() {
  10. console.log(this);
  11. // 如果想要从路由规则中,提取匹配到的参数进行使用,可以使用 this.props.match.params.*** 来访问
  12. return <div>
  13. {/* Movie --- {this.props.match.params.type} --- {this.props.match.params.id} */}
  14. Movie --- {this.state.routeParams.type} --- {this.state.routeParams.id}
  15. </div>
  16. }
  17. }

5. components/About.jsx

  1. import React from 'react'
  2. export default class About extends React.Component {
  3. constructor(props) {
  4. super(props)
  5. this.state = {}
  6. }
  7. render() {
  8. return <div>
  9. About
  10. </div>
  11. }
  12. }

四、路由匹配规则

默认配置:

路径 location.pathname 是否匹配
/one /one
/one /one/
/one /one/111
/one /one/aaa/bbb

**

exact配置:

  • exact属性为true时路径中的hash值必须和path完全一致才渲染对应的组件,如果为false则’/‘也可以匹配’/xxx’ | 路径 | location.pathname | exact | 是否匹配 | | :—- | :—- | :—- | :—- | | /one | /one/two | true | 否 | | /one | /one/two | false | 是 |

strict配置:

  • strict属性主要就是匹配反斜杠,规定是否匹配末尾包含反斜杠的路径,如果strict为true,则如果path中不包含反斜杠结尾,则他也不能匹配包含反斜杠结尾的路径 | 路径 | location.pathname | strict | 是否匹配 | | :—- | :—- | :—- | :—- | | /one/ | /one | true | 否 | | /one/ | /one/ | true | 是 | | /one/ | /one/two | true | 是 |

五、Switch和Redirect

Switch

表示路由互斥,如果没有Switch,会根据路由找到所有匹配的组件显示
比如http://localhost:3000/#/user 会找到/、/user所匹配的路由(下面home没有找到是因为精确匹配了)

Redirect

没有匹配到路径的时候重定向到根路径

  1. import { HashRouter, Route, Link, Switch,Redirect} from 'react-router-dom'
  2. render() {
  3. return (
  4. <HashRouter>
  5. <Switch>
  6. {/*
  7. path:/ 表示访问根路径的情况下默认载入home组件
  8. exact精确匹配,为了给其他组件一个机会获取到url改变
  9. */}
  10. <Route path='/' exact component={Home}/>
  11. <Route path='/city' component={City}/>
  12. {/*
  13. strict 在确定路径是否与当前URL匹配时,将考虑路径后的斜线;
  14. */}
  15. <Route path='/login/' strict component={Login}/>
  16. <Route path='/user' component={User}/>
  17. <Route path='/search/:category/' strict component={Search}/>
  18. <Route path='/detail/:id' component={Detail}/>
  19. {/*没有匹配到路径的时候重定向到根路径*/}
  20. <Redirect to="/" />
  21. </Switch>
  22. </HashRouter>
  23. )
  24. }