React路由
- 一、SPA的理解
- 二、路由的理解
- 三、react-router-dom
- 四、路由的基本使用
- 五、NavLink的使用(v5和v6有区别)
- 六、对NavLink二次封装
- 七、Switch的使用(v6已经移除switch,替换为Routes)
- 八、解决多级路径刷新页面样式丢失的问题
- 九、路由的严格匹配与模糊匹配
- 十、Redirect的使用(v6版本已经废除,用Navigate 代替)
- 十一、嵌套路由(v5和v6使用起来不一样)
- 十二、向路由组件传递params参数
- 十三、向路由组件传递search参数
- 十四、向路由组件传递state参数
- 十四、push与replace模式
- 十五、编程式路由导航(v5和v6不同)
- 十六、withRouter的使用(v6版本已经移除了)
- 十七、BrowserRouter与HashRouter的区别
- 十八、 总结
一、SPA的理解
- 单页Web应用(single page web application,SPA)。
- 整个应用只有一个完整的页面。
- 点击页面中的链接不会刷新页面,只会做页面的局部更新。
- 数据都需要通过ajax请求获取, 并在前端异步展现。
二、路由的理解
-
什么是路由?
1). 一个路由就是一个映射关系(key:value)
2). key为路径, value可能是function或component -
路由分类
-
后端路由:
1)、 理解: value是function, 用来处理客户端提交的请求。
2)、 注册路由: router.get(path, function(req, res))
3)、 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据 -
前端路由:
1)、 浏览器端路由,value是component,用于展示页面内容。
2)、注册路由:<Route path="/test" component={Test}>
3)、工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件 -
前端路由的基石
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>前端路由的基石_history</title> </head> <body> <a href="http://www.atguigu.com" onclick="return push('/test1') ">push test1</a><br><br> <button onClick="push('/test2')">push test2</button><br><br> <button onClick="replace('/test3')">replace test3</button><br><br> <button onClick="back()"><= 回退</button> <button onClick="forword()">前进 =></button> <script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script> <script type="text/javascript"> // let history = History.createBrowserHistory() //方法一,直接使用H5推出的history身上的API let history = History.createHashHistory() //方法二,hash值(锚点) function push (path) { history.push(path) return false } function replace (path) { history.replace(path) } function back() { history.goBack() } function forword() { history.goForward() } history.listen((location) => { console.log('请求路由路径变化了', location) }) </script> </body> </html>
-
三、react-router-dom
1、理解
- react的一个插件库。
- 专门用来实现一个SPA应用。
- 基于react的项目基本都会用到此库。
2、相关API
1)、内置组件
1. <BrowserRouter>
2. <HashRouter>
3. <Route>
4. <Redirect>
5. <Link>
6. <NavLink>
7. <Switch>
2)、其它
1. history对象
2. match对象
3. withRouter函数
四、路由的基本使用
用实例进行解释,知识点全在注释中
index.jsx
//引入react核心库
import React from 'react'
//引入ReactDOM
import ReactDOM from 'react-dom'
//
import {
BrowserRouter} from 'react-router-dom'
//引入App
import App from './App'
ReactDOM.render(
<BrowserRouter>
<App/>
</BrowserRouter>,
document.getElementById('root')
)
App.jsx
import React, {
Component } from 'react'
import {
Link, Route } from 'react-router-dom'
import Home from './components/Home'
import About from './components/About'
export default class App extends Component {
render () {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div className="row">
<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中靠路由链接实现切换组件--编写路由链接 */}
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{
/* 注册路由,v6版本需要用routes包裹route,并且component变为了element,element里是一个组件,path引号里的路径不需要'/' */}
<Route path="/about" component={
About} />
<Route path="/home" component={
Home} />
{
/* v6版本这样写 */}
{
/* <Routes>
<Route path='home' element={<Home />} />
<Route path='about' element={<About />} />
</Routes> */}
</div>
</div>
</div>
</div>
</div>
)
}
}
About.jsx
import React, {
Component } from 'react'
export default class About extends Component {
render() {
return (
<h3>我是About的内容</h3>
)
}
}
Home.jsx
import React, {
Component } from 'react'
export default class Home extends Component {
render() {
return (
<h3>我是Home的内容</h3>
)
}
}
五、NavLink的使用(v5和v6有区别)
目录结构
index.jsx
//引入react核心库
import React from 'react'
//引入ReactDOM
import ReactDOM from 'react-dom'
//
import {
BrowserRouter} from 'react-router-dom'
//引入App
import App from './App'
ReactDOM.render(
<BrowserRouter>
<App/>
</BrowserRouter>,
document.getElementById('root')
)
App.jsx
import React, {
Component } from 'react'
import {
NavLink, Route } from 'react-router-dom'
import Home from './pages/Home' //Home是路由组件
import About from './pages/About' //About是路由组件
import Header from './components/Header' //Header是一般组件
export default class App extends Component {
render () {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<Header />
</div>
</div>
<div className="row">
<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中靠路由链接实现切换组件--编写路由链接 */}
<NavLink activeClassName="atguigu" className="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName="atguigu" className="list-group-item" to="/home">Home</NavLink>
{
/*
v6版本不能这样写,V6版本NavLink移除了activeClassName 和activeStyle
<NavLink style={({ isActive }) => ({ color: isActive ? '#FFF' : '#333', backgroundColor: isActive ? 'orange' : 'none' })} className="list-group-item" to="/about">About</NavLink>
<NavLink style={({ isActive }) => ({ color: isActive ? '#FFF' : '#333', backgroundColor: isActive ? 'orange' : 'none' })} className="list-group-item " to="/home">Home</NavLink>
或者这样写
<NavLink className={({ isActive }) => (isActive ? " afei" : "list-group-item")} to="/about">About</NavLink>
<NavLink className={({ isActive }) => (isActive ? " afei" : "list-group-item")} to="/home">Home</NavLink>
注意:这里的afei是我自己定义的类名,list-group-item是bootstrap的,活跃状态就显示我定义的
或者自己封装一个NavLink组件
*/}
</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>
</div>
</div>
)
}
}
components下的Header下的index.jsx
import React, {
Component } from 'react'
export default class Header extends Component {
render() {
// console.log('Header组件收到的props是',this.props);
//v6版本收不到
return (
<div className="page-header"><h2>React Router Demo</h2></div>
)
}
}
pages下的About下的index.jsx
import React, {
Component } from 'react'
export default class About extends Component {
render() {
// console.log('About组件收到的props是',this.props);
//v6版本收不到
return (
<h3>我是About的内容</h3>
)
}
}
pages下的Home下的index.jsx
import React, {
Component } from 'react'
export default class Home extends Component {
render() {
return (
<h3>我是Home的内容</h3>
)
}
}
六、对NavLink二次封装
其他代码和上面都一样,只有下面的与上面的有所不同
在components里新增加一个MyNavLink文件夹及组件
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}