一、概念
SPA
1、单页Web应用(single page web application,SPA)。
2、整个应用只有一个完整的页面。
3、点击页面中的链接不会刷新页面,只会做页面的局部更新。
4、数据都需要通过 ajax 请求获取,并在前端异步展现。
路由
什么是路由?
1、一个路由就是一个映射关系(key: value)
2、key 为路径,value 可能是 function 或 component
路由分类
1、后端路由
理解:value 是 function,用来处理客户端提交的请求。
注册路由: router.get(path, function(req, res))
工作过程:当 node 接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据。
2、前端路由
理解:浏览器端路由,value 是 component,用于展示页面内容。
注册路由: `<Route path="/test" component={Test}>`
工作过程:当浏览器的 path 变为 /test 时,当前路由组件就会变为 Test 组件
react-router-dom
1、react 的一个插件库。
2、专门用来实现一个 SPA 应用。
3、基于 react 的项目基本都会用到此库。
4、安装 react-router-dom:$ npm install --save react-router-dom
react-router:为 React 应用提供了路由的核心功能;
react-router-dom:基于 react-router,加入了在浏览器运行环境下的一些功能;
二、react-router-dom 相关 API
内置组件
1、<BrowserRouter>
2、<HashRouter>
3、<Route>
4、<Redirect>
5、<Link>
6、<NavLink>
7、<Switch>
其它
1、history 对象
2、match 对象
3、withRouter 函数
三、react-router-dom 使用
1、基本路由使用
明确好界面中的导航区、展示区
导航区的 a 标签改为 Link 标签 <Link to="/xxxxx">Demo</Link>
展示区写 Route 标签进行路径的匹配 <Route path='/xxxx' component={Demo}/>
的最外侧包裹了一个或`
2、路由组件 与 一般组件区别
写法不同
一般组件:<Demo/>
路由组件:<Route path="/demo" component={Demo}/>
存放位置不同
一般组件:components 目录
路由组件:pages 目录
接收到的 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 指定样式名,NavLink 选中样式类名默认为active。
<NavLink activeClassName="selected" className="list-group-item" to="/about">About</NavLink>
标签体内容(组件标签)是一个特殊的标签属性,通过 this.props.children 可以获取标签体内容。
4、Switch 的使用
通常情况下,path 和 component 是一一对应的关系。
Switch 可以提高路由匹配效率(单一匹配)。
5、解决多级路径刷新页面样式丢失的问题
public/index.html 中 引入样式时不写 ./ 写 / (常用)
public/index.html 中 引入样式时不写 ./ 写 %PUBLIC_URL% (常用)
使用 HashRouter (#后面的内容都认为是前端的东西,不会发送给服务端)
6、路由的严格匹配与模糊匹配
默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)
开启严格匹配:<Route exact={true} path="/about" component={About}/>
严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
7、Redirect 的使用
一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到 Redirect 指定的路由
具体编码
javascript
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
8、嵌套路由
注册子路由时要写上父路由的 path 值
路由的匹配是按照注册路由的顺序进行的
9、向路由组件传递参数
params 参数
路由链接(携带参数):<Link to='/demo/test/tom/18'}>详情</Link>
注册路由(声明接收):<Route path="/demo/test/:name/:age" component={Test}/>
接收参数:this.props.match.params
search参数
路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
接收参数:this.props.location.search
备注:获取到的 search 是 urlencoded 编码字符串,需要借助 querystring 解析
安装:$ npm install querystring
引入:import qs from 'querystring'
使用:qs.parse(str)
state参数
路由链接(携带参数):<Link to={``{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
接收参数:this.props.location.state
备注:虽然地址栏上没有携带参数,但是刷新也可以保留住参数
依赖于浏览器history对象,清理浏览器缓存后,this.props.location.state 为 null,书写代码时需要做兼容处理
10、编程式路由导航
借助 this.props.history 对象上的 API 对操作路由跳转、前进、后退
javascript
this.prosp.history.push()
this.prosp.history.replace()
this.prosp.history.goBack() // 回退
this.prosp.history.goForward() // 前进
this.prosp.history.go(n) // 由传入参数决定,负数后退,正数前进
11、withRouter
withRouter 可以加工一般组件,让一般组件具备路由组件所特有的 API
withRouter 的返回值是一个新组件
javascript
import { withRouter } from 'react-router-dom'
class Header extends Component {}
export default withRouter(Header)
12、BrowserRouter 与 HashRouter的区别
底层原理不一样:
BrowserRouter 使用的是 H5 的 history API,不兼容IE9及以下版本。
HashRouter使用的是URL的哈希值。
path 表现形式不一样:
BrowserRouter 的路径中没有#,例如:localhost:3000/demo/test
HashRouter 的路径包含 #,例如:localhost:3000/#/demo/test
刷新后对路由state参数的影响:
BrowserRouter 没有任何影响,因为state保存在history对象中。
HashRouter 刷新后会导致路由state参数的丢失!!!
备注:HashRouter 可以用于解决一些路径错误相关的问题。(例如:多层路由样式丢失)