脚手架编译打包出来的是 SPA 单页面应用 所依赖的核心就是前端路由
安装:指定5版本
npm i react-router-dom@5
一、入口文件要包裹 HashRouter / BrowserRouter
// 相当于 main.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import {HashRouter,BrowserRouter} from 'react-router-dom'
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
// React.StrictMode 标签 严格模式 检查
<React.StrictMode>
<HashRouter>
<App />
</HashRouter>
</React.StrictMode>
);
// 页面性能分析 需要 web-vitals库的支持
reportWebVitals();
react-router-dom 一些内置组件使用的介绍:
- Link 路由跳转的按钮 to = '路径名'
- NavLink 带有高亮效果的 路由导航(添加 active类名)
- Route path = 要匹配的路径 component = 对应展示的组件 exact属性 开启严格匹配
- Swicth 开启精准匹配 当匹配上一个路径时 显示对应组件 不再继续向下匹配
- Redirect 默认指向 没有匹配上时就对应这个
//import axios from 'axios';
import React, { Component } from 'react'
import './App.css';
import {NavLink,Route,Switch,Redirect} from 'react-router-dom'
import Home from './component/Home'
import About from './component/About'
import Formerly from './component/Formerly'
import Case from './page/Case'
import MyNavLink from './component/MyNavLink'
export default class App extends Component {
render(){
return (
<div className="container">
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<Formerly a={8755}/>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
<NavLink className='list-group-item' to='/about'>About</NavLink>
<NavLink className='list-group-item' to='/home'>Home</NavLink>
<NavLink className='list-group-item' to='/case'>Case</NavLink>
自己封装:
<MyNavLink to="about/b/c">关于</MyNavLink>
<MyNavLink to="home">首页</MyNavLink>
<MyNavLink to="case" children="案例"></MyNavLink>
模糊匹配精准匹配
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Switch>
<Route path='/about' exact component={About}></Route>
<Route path='/home' component={Home}></Route>
<Route path='/case' component={Case}></Route>
<Route path='/about' component={Formerly}></Route>
<Redirect to="/home"/>
</Switch>
</div>
</div>
</div>
</div>
Redirect写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由 <br></br>
普通about 开启了严格匹配 Formerly没有开启 所以 about/b/c 关于 会导向 Formerly
</div>
)
}
}
封装MyNavLink
相同的类名比较多时可以 自行封装一下 接收到的props 直接展开到 组件中
传入 children 就是写入标签内的数据
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
export default class index extends Component {
render() {
return (
<NavLink {...this.props} className="list-group-item"></NavLink>
)
}
}
路由组件与一般组件
1.写法不同 引用方式不同
一般组件:<Demo/> 手动固定引入
路由组件:<Route path="/demo" component={Demo}/> 用到时再加载
2.接收到的props不同:
一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到三个固定的属性 history location match
嵌套路由:
1.注册子路由时要写上父路由的path值
2.路由的匹配是按照注册路由的顺序进行的
这里以 Case组件为例
import React, { Component } from 'react'
import New from './New'
import Message from './Message'
import { Link,Route } from 'react-router-dom'
export default class Case extends Component {
render() {
//console.log('路由组件会有默认props',this.props,'这里也执行了两次?')
return (
<div>
<h3>
Case组件是保存在 page里的路由组件
<br />
这里显示的是嵌套路由
</h3>
<Link to='/case/new'>新闻</Link>
<Link to='/case/message'>消息</Link>
<Route path="/case/new" component={New}></Route>
<Route path="/case/message" component={Message}></Route>
</div>
)
}
}
路由传递参数
1.params 传参
路径跳转时直接写上 数据 / 分割
<Link to={`/case/new/detail/947/美食`}>美食</Link>
匹配展示时 要接上占位符 :标识
<Route path="/case/new/detail/:id/:title" component={Detail}></Route>
在跳转的组件内部 this.props.match.params 解构出来 使用
const {id,title} = this.props.match.params
2.search 传参
相当于url中的query字符串 ?开始 &分隔
<Link to={`/case/new/detail?id=857&title=汽车`}>汽车</Link>
匹配展示时不用添加参数
<Route path="/case/new/detail" component={Detail}></Route>
接收 search 参数 在 this.props.location 里 但它是查询字符转 想用要转化成对象
const {search} = this.props.location
3.state传参
单独写对象 pathname 路径名 state传递的参数分开
<Link to={{pathname:'/case/new/detail',state:{id:666,title:娱乐}}}>娱乐</Link>
匹配展示时不用添加参数
<Route path="/case/new/detail" component={Detail}></Route>
接收 state 参数 在 this.props.location 里 它不会显示在地址栏
const {id,title} = this.props.location.state
完整代码:
Case/New
import React, { Component } from 'react'
import { Link,Route } from 'react-router-dom'
import Detail from './Detail'
export default class New extends Component {
state={
NewArr:[
{id:"101",title:'新闻1'},
{id:"201",title:'新闻2'},
{id:"301",title:'新闻3'}
]
}
pushS = (id,title) =>{
// push跳转 携带 state参数
this.props.history.push('/case/new/detail',{id,title})
// search
//this.props.history.push(`/case/new/detail?id=${id}&title=${title}`)
// params
//this.props.history.push(`/case/new/detail/${id}/${title}`)
}
replaceS = (id,title) => {
// replace跳转 携带 state参数
this.props.history.replace('/case/new/detail',{id,title})
// search
//this.props.history.replace(`/case/new/detail?id=${id}&title=${title}`)
// params
//this.props.history.push(`/case/new/detail/${id}/${title}`)
}
render() {
const {NewArr} = this.state
return (
<div>
<ul>
{
NewArr.map((x) =>{
return (
<li key={x.id}>
{/**
* 向组件传递 params 参数
* <Link to={`/case/new/detail/${x.id}/${x.title}`}>{x.title}</Link>
* 向组件传递 search 参数
* <Link to={`/case/new/detail?id=${x.id}&title=${x.title}`}>{x.title}</Link>
* state
*
*/}
<Link to={{pathname:'/case/new/detail',state:{id:x.id,title:x.title}}}>{x.title}</Link>
<button onClick={() => this.pushS(x.id,x.title)}>push编程跳转路由</button>
<button onClick={() => this.replaceS(x.id,x.title)}>replace编程跳转路由</button>
</li>
)
})
}
</ul>
<hr />
{/** 声明接收 params 参数
* <Route path="/case/new/detail/:id/:title" component={Detail}></Route>
* search 参数无需声明接收 正常注册路由即可
* state 参数无需声明接收 正常注册路由即可
*
*/}
<Route path="/case/new/detail" component={Detail}></Route>
</div>
)
}
}
Detail:
import React, { Component } from 'react'
//import qs from 'querystring'
const DetailData = [
{id:"101",context:'鼎立中原'},
{id:"201",context:'哑铃战术'},
{id:"301",context:'西南追歼'},
]
export default class Detail extends Component {
render() {
console.log(this.props)
// 接收params 参数
// const {id,title} = this.props.match.params
// 接收 search 参数
// const {search} = this.props.location
// const {id,title} = qs.parse(search.slice(1))
// 接收 state 参数
const {id,title} = this.props.location.state
const findRes = DetailData.find(x =>{
return x.id === id
})
return (
<ul>
<li>ID:{id}</li>
<li>TITLE:{title}</li>
<li>{JSON.stringify(findRes)}</li>
</ul>
)
}
}
编程式路由
之前都是通过 Link NavLink 来实现跳转 这是声明式导航
也可以利用API实现 编程式导航
使用场景:满足条件自动跳转、定时器事件满后自动跳转......
- this.props.history.push() push 跳转(压栈)有记录
-
this.props.history.replace() replace 跳转 直接替换
-
this.props.history.goBack() 退后一步
-
this.props.history.goForward() 前进一步
-
this.props.history.go() 填写数字 正数前进 负数退后
也可以 携带 三种参数
pushS = (id,title) =>{
// push跳转 携带 state参数
this.props.history.push('/case/new/detail',{id,title})
// search
//this.props.history.push(`/case/new/detail?id=${id}&title=${title}`)
// params
//this.props.history.push(`/case/new/detail/${id}/${title}`)
}
replaceS = (id,title) => {
// replace跳转 携带 state参数
this.props.history.replace('/case/new/detail',{id,title})
// search
//this.props.history.replace(`/case/new/detail?id=${id}&title=${title}`)
// params
//this.props.history.push(`/case/new/detail/${id}/${title}`)
}