React 路由
1.ReactRouter 5.x
功能概述:点击切换展示区内容,并切换浏览器地址 /about /home
About 组件
import React, { Component } from 'react'
export default class About extends Component {
render() {
return (
<h3>
我是About的内容
</h3>
)
}
}
Home组件
import React, { Component } from 'react'
export default class Home extends Component {
render() {
return (
<h3>
我是Home的内容
</h3>
)
}
}
React6.x-App.jsx
import React, { Component } from 'react'
import { Link, Route , Routes} from 'react-router-dom'
import About from './components/About'
import Home from './components/Home'
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">
{/* 点击链接,修改浏览器地址-编写路由链接 */}
<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">
{/* 注册路由 */}
<Routes>
<Route path="/about" element={<About/>} />
<Route path="/home" element={<Home/>} />
</Routes>
{/*React5.x 可以直接用 Route 标签,不使用 element 元素*/}
{/*
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
*/}
</div>
</div>
</div>
</div>
</div>
)
}
}
2.路由组件和普通组件:
3.Link 标签没有高亮样式,使用 NavLink 就具有高亮样式,可以给 NavLink 添加 activeClassName 属性指定样式
<div className="list-group">
{/* 点击链接,修改浏览器地址-编写路由链接 */}
<NavLink activeClassName="navactive" className="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName="navactive" className="list-group-item" to="/home">Home</NavLink>
</div>
然后在 public/index.html 中添加样式
<style>
.navactive{
background-color: orange !important;
color: white !important
}
</style>
4.如果存在多个 NavLink 标签看起来就很繁琐,我们可以自己封装一个 MyNavLink,下面是部分代码片段
App.js 中修改部分
// 对于通过标签体中传递的值,会自动存储到 children 属性中
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
新创建的普通组件 MyNavLink
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
export default class MyNavLink extends Component {
render() {
return (
<NavLink activeClassName="navactive" className="list-group-item" {...this.props}/>
)
}
}
5.如果 Route 特别多的话,我们希望匹配上了就不要继续向下匹配了,我们可以通过 Switch 组件来完成,匹配到对应路径就结束匹配
/*如果不使用 Switch 组件在点击 /home 就会出现两个 Home 组件渲染出来的数据*/
<Switch>
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
<Route path="/home" component={Home} />
</Switch>
6.多级路径解决样式丢失的三种办法
样式是在 index.html 中引入的 <link rel="stylesheet" href="./css/bootstrap.css" type="text/css">
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 点击链接,修改浏览器地址-编写路由链接 */}
<MyNavLink to="/bonbons/about">About</MyNavLink>
<MyNavLink to="/bonbons/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
<Switch>
<Route path="/bonbons/about" component={About} />
<Route path="/bonbons/home" component={Home} />
</Switch>
</div>
</div>
</div>
</div>
点击按钮后刷新,就会找不到样式,返回 index.html 的内容
- 修改引入样式:
<link rel="stylesheet" href="/css/bootstrap.css" type="text/css">
【去掉相对路径的点】 - 修改引入样式:
<link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css" type="text/css">
【使用public的绝对路径】 - 修改路由器的类型:
import React from 'react'
import ReactDOM from 'react-dom'
import { HashRouter } from 'react-router-dom'
import App from './App.jsx'
ReactDOM.render(
<HashRouter>
<App />
</HashRouter>,
document.getElementById('root')
)
7.Link和Route之间默认是模糊匹配
- 意思就是只要Link从头开始包含Route中的path,那么就可以匹配上
- 只要不出现问题,我们就不用开启严格匹配,可以通过给 Route 添加属性
exact
或exact={true}
开启严格匹配
8.使用重定向组件,可以指定默认路径
// 兜底作用
<Switch>
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
<Redirect to="about"/>
</Switch>
9.如果想使用嵌套路由,那么需要子路由以父路由地址开头,而且父路由不能使用严格匹配,因为只有执行到子组件注册路由的部分才能正确匹配到对应的组件
import React, { Component } from 'react'
import { Route, Redirect } from 'react-router-dom'
import MyNavLink from '../../components/MyNavLink'
import Message from './Message'
import News from './News'
export default class Home extends Component {
render() {
return (
<div>
<h3>
我是Home的内容
</h3>
<div>
<ul className="nav nav-tabs">
<li>
<MyNavLink to="/home/news">News</MyNavLink>
</li>
<li>
<MyNavLink to="/home/message">Message</MyNavLink>
</li>
</ul>
{/* 注册路由 */}
<Route path="/home/news" component={News} />
<Route path="/home/message" component={Message} />
<Redirect to="/home/news" />
</div>
</div>
)
}
}
10.如何向路由传递参数呢?
我们给 message 添加子组件,显示具体的消息
11.向路由组件传递参数的几种方式
(1)通过 params 参数传递
Detail组件
import React, { Component } from 'react'
const datas = [
{ id: '1', content: '你好,中国' },
{ id: '2', content: '你好,北京' },
{ id: '3', content: '你好,未来' },
]
export default class Detail extends Component {
render() {
const { id, title } = this.props.match.params
const findResult = datas.find((data) => {
return data.id === id
})
return (
<div>
<ul>
<li>id:{id}</li>
<li>title:{title}</li>
<li>content:{findResult.content}</li>
</ul>
</div>
)
}
}
Message组件
import React, { Component } from 'react'
import { Route, Link } from 'react-router-dom'
import Detail from './Detail'
const messages = [
{ id: '1', title: 'message001' },
{ id: '2', title: 'message002' },
{ id: '3', title: 'message003' },
]
export default class Message extends Component {
render() {
return (
<div>
<ul>
{
messages.map((msgObj) => {
return (
<li key={msgObj.id}>
<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
</li>
)
})
}
</ul>
<hr/>
<Route path="/home/message/detail/:id/:title" component={Detail}/>
</div>
)
}
}
(2)通过 search 参数传递
// Detail 组件中的区别
const {id, title} = qs.parse(this.props.location.search.slice(1))
// Message 组件中的区别
<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
<Route path="/home/message/detail" component={Detail}/>
(3)通过 state 参数传递
// Detail 组件中的区别
const {id, title} = this.props.location.state
// Message 组件中的区别
<Link to={{pathname:'/home/message/detail', state:{id:msgObj.id, title:msgObj.title}}}>{msgObj.title}</Link>
<Route path="/home/message/detail" component={Detail}/>
12.利用 history 实现编程式路由导航
this.props.history.push(path, state)
this.props.history.replace(path, state)
this.props.history.push(path, state)
this.props.history.goBack()
this.props.history.goForward()
this.props.history.go(n) // n > 0 前进n步, n < 0 后退 n 步
13.使用 withRouter 可以让一般组件使用路由组件的 API
14.HashRouter、BrowserRouter 的区别