一、前言
1.SPA的理解
- 单页Web应用(single page web application,SPA)。
- 整个应用只有一个完整的页面。
- 点击页面中的链接不会刷新页面,只会做页面的局部更新。
- 数据都需要通过ajax请求获取, 并在前端异步展现。
2.路由的理解
(1)什么是路由?
一个路由就是一个映射关系(key:value)。其中:key为路径, value可能是function或component。
(2)路由分类
后端路由:
- 理解: value是function, 用来处理客户端提交的请求。
- 注册路由: router.get(path, function(req, res))
- 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
前端路由:
- 浏览器端路由,value是component,用于展示页面内容。
- 注册路由: <Route path="/test" component={Test}>
- 工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件
3.react-router-dom的理解
react的一个插件库,专门用来实现一个SPA应用。基于react的项目基本都会用到此库。
二、react-router-dom相关API
内置组件
1.<BrowserRouter>
2.<HashRouter>
3.<Route>
4.<Redirect>
5.<Link>
6.<NavLink>
7.<Switch>
其它
1.history对象
2.match对象
3.withRouter函数
三、基本路由
1.路由的基本使用
(1)明确好界面中的导航区、展示区
(2)导航区的a标签改为Link标签
<Link to="/xxxxx">Demo</Link>
(3)展示区写Route标签进行路径的匹配
<Route path='/xxxx' component={Demo}/>
(4)<App>的最外侧包裹了一个<BrowserRouter>或<HashRouter>
2.路由组件与一般组件
(1)写法不同:
一般组件:<Demo/>
路由组件:<Route path="/demo" component={Demo}/>
(2)存放位置不同:
一般组件:components
路由组件:pages
(3)接收到的props不同:
一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到三个固定的属性
history:
go: ƒ go(n)
goBack: ƒ goBack()
goForward: ƒ goForward()
push: ƒ push(path, state)
replace: ƒ replace(path, state)
location:
pathname: "/about"
search: ""
state: undefined
match:
params: {}
path: "/about"
url: "/about"
3.NavLink与封装NavLink
NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
// App.jsx
import Home from './pages/Home' //Home是路由组件
import About from './pages/About' //About是路由组件
import MyNavLink from './components/MyNavLink'
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 原生html中,靠<a>跳转不同的页面 */}
{/* <a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a> */}
{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
</div>
</div>
// /components/MyNavLink/index.jsx
import React, { Component } from 'react'
import {NavLink} from 'react-router-dom'
export default class MyNavLink extends Component {
render() {
// console.log(this.props);
return (
<NavLink activeClassName="atguigu" className="list-group-item" {...this.props}/>
)
}
}
4.Switch的使用
通常情况下,path和component是一一对应的关系。Switch可以提高路由匹配效率(单一匹配)。
{/* 注册路由 */}
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={Test}/>
</Switch>
5.解决多级路径刷新页面样式丢失的问题
(1)public/index.html 中 引入样式时不写 ./ 写 / (常用)
(2)public/index.html 中 引入样式时不写 ./ 写 %PUBLIC_URL% (常用)
(3)使用HashRouter
6.路由的严格匹配与模糊匹配
(1)默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)
(2)开启严格匹配:<Route exact={true} path="/about" component={About}/>
(3)严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
7.Redirect的使用
重定向设置默认选择的路由
(1)一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
(2)具体编码:
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
四、嵌套路由(多级路由)
(1)注册子路由时**要写上父路由的path值**
(2)路由的匹配是按照**注册路由的顺序**进行的
五、向路由组件传递参数
1.params参数
路由链接(携带参数):<Link to='/demo/test/tom/18'}>详情</Link>
注册路由(声明接收):<Route path="/demo/test/:name/:age" component={Test}/>
接收参数:this.props.match.params
2.search参数
路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
接收参数:this.props.location.search
备注:获取到的search是urlencoded编码字符串,需要借助querystring解析
3.state参数
路由链接(携带参数):<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
接收参数:this.props.location.state
备注:刷新也可以保留住参数
六、路由跳转
1.编程式路由导航
借助this.prosp.history对象上的API对操作路由跳转、前进、后退
-this.props.history.push()
-this.props.history.replace()
-this.props.history.goBack()
-this.props.history.goForward()
-this.props.history.go()
// 不留下痕迹
replaceShow = (id,title)=>{
//replace跳转+携带params参数
//this.props.history.replace(`/home/message/detail/${id}/${title}`)
//replace跳转+携带search参数
// this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)
//replace跳转+携带state参数
this.props.history.replace(`/home/message/detail`,{id,title})
}
// 不留下痕迹
pushShow = (id,title)=>{
//push跳转+携带params参数
// this.props.history.push(`/home/message/detail/${id}/${title}`)
//push跳转+携带search参数
// this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)
//push跳转+携带state参数
this.props.history.push(`/home/message/detail`,{id,title})
}
2.一般组件具备路由组件所特有的API
withRouter可以加工一般组件,让一般组件具备路由组件所特有的API。withRouter的返回值是一个新组件。
class Header extends Component {
back = ()=>{
this.props.history.goBack()
}
forward = ()=>{
this.props.history.goForward()
}
go = ()=>{
this.props.history.go(-2)
}
render() {
console.log('Header组件收到的props是',this.props);
return (
<div className="page-header">
<h2>React Router Demo</h2>
<button onClick={this.back}>回退</button>
<button onClick={this.forward}>前进</button>
<button onClick={this.go}>go</button>
</div>
)
}
}
export default withRouter(Header)
七、BrowserRouter与HashRouter的区别
1.底层原理不一样:
- BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
- HashRouter使用的是URL的哈希值。
2.path表现形式不一样
- BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
- HashRouter的路径包含#,例如:localhost:3000/#/demo/test
3.刷新后对路由state参数的影响
- BrowserRouter没有任何影响,因为state保存在history对象中
- HashRouter刷新后会导致路由state参数的丢失,因为没有用history的API
4.备注:HashRouter可以用于解决一些路径错误相关的问题。