官方文档
一、前端路由的两种实现方案
- hash : hash原本的作用是为一个很长的文档页添加锚点信息,它自带不改变url刷新页面的功能,所以自然而然被用单页面应用程序中了。
- history : 应该说history是主流的解决方案,浏览器的前进后退用的就是这个,它是window对象下的,以前的history提供的方法只能做页面之间的前进后退,如下:
history.go(number|URL) 可加载历史列表中的某个具体的页面
history.forward() 可加载历史列表中的下一个 URL
history.back() 可加载历史列表中的前一个 URL
为了在不刷新浏览器的情况下,创建新的浏览记录并插入浏览记录队列中,html5新增了如下方法:
- history.pushState(state, title, url)
- 添加一条历史记录, state用于传递参数,可以为空。title是设置历史记录的标题,可以为空。url是历史记录的URL,不可以为空。
- 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
npm install react-router-dom -S
// 1. 导入包
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App.jsx'
// 使用 render 函数渲染 虚拟DOM
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 中,只能有唯一的一个根元素
// 在一个网站中,只需要使用 唯一的一次
这是网站的APP根组件
<Link to="/home">首页</Link>
<Link to="/movie/top250/10">电影</Link>
<Link to="/about">关于</Link>
<hr />
{/* Route 创建的标签,就是路由规则,其中 path 表示要匹配的路由,component 表示要展示的组件 */}
{/* 在 vue 中有个 router-view 的路由标签专门用来放置匹配到的路由组件的,但是在 react-router 中并没有类似于这样的标签,而是直接把 Route 标签当作的坑(占位符) */}
{/* Route 具有两种身份:1. 它是一个路由匹配规则; 2. 它是一个占位符,表示将来匹配到的组件都放到这个位置, 如果想让路由规则进行精确匹配,可以为 Route添加 exact 属性,表示启用精确匹配模式 */}
<Route path="/home" component={Home}></Route>
<hr />
{/* 注意:默认情况下,路由中的规则是模糊匹配的,如果路由可以部分匹配成功,就会展示这个路由对应的组件 */}
{/* 如果要匹配参数,可以在匹配规则中使用 : 修饰符,表示这个位置匹配到的是参数 */}
<Route path="/movie/:type/:id" component={Movie} exact></Route>
<hr />
<Route path="/about" component={About}></Route>
</div>
</HashRouter>
} }
<a name="Kkqrx"></a>
#### 3. components/Home.jsx
```javascript
import React from 'react'
export default class Home extends React.Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
return <div>
Home
</div>
}
}
4. components/Movie.jsx
import React from 'react'
export default class Movie extends React.Component {
constructor(props) {
super(props)
this.state = {
routeParams: props.match.params
}
}
render() {
console.log(this);
// 如果想要从路由规则中,提取匹配到的参数进行使用,可以使用 this.props.match.params.*** 来访问
return <div>
{/* Movie --- {this.props.match.params.type} --- {this.props.match.params.id} */}
Movie --- {this.state.routeParams.type} --- {this.state.routeParams.id}
</div>
}
}
5. components/About.jsx
import React from 'react'
export default class About extends React.Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
return <div>
About
</div>
}
}
四、路由匹配规则
默认配置:
路径 | 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
没有匹配到路径的时候重定向到根路径
import { HashRouter, Route, Link, Switch,Redirect} from 'react-router-dom'
render() {
return (
<HashRouter>
<Switch>
{/*
path:/ 表示访问根路径的情况下默认载入home组件
exact精确匹配,为了给其他组件一个机会获取到url改变
*/}
<Route path='/' exact component={Home}/>
<Route path='/city' component={City}/>
{/*
strict 在确定路径是否与当前URL匹配时,将考虑路径后的斜线;
*/}
<Route path='/login/' strict component={Login}/>
<Route path='/user' component={User}/>
<Route path='/search/:category/' strict component={Search}/>
<Route path='/detail/:id' component={Detail}/>
{/*没有匹配到路径的时候重定向到根路径*/}
<Redirect to="/" />
</Switch>
</HashRouter>
)
}