React-Router-Dom(路由版本[5])
简介
- React的一个插件库
- 用于实现SPA应用
- 基于React的项目基本都用
API
- <BrowserRouter>
- <HashRouter>
- <Route>
- <Redirect>
- <Link>
- <NavLink>
- <Switch>
其它
- history对象
- match对象
- withRouter函数
添加依赖
yarn add react-router-dom@5
使用
BrowserRouter+Link+Route
import {Link, BrowserRouter, Route} from 'react-router-dom'
// 需要在最外面包裹一个路由管理器 也可以包在index.js的app组件外面
<BrowserRouter>
<div style={{textAlign: 'center'}}>
<div>
{/*定义导航连接*/}
<Link to="/home">Home</Link>
<br/>
<Link to="/about">About</Link>
</div>
<div>
{/*注册路由*/}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
</div>
</BrowserRouter>
BrowserRouter+NavLink+Route
和Link功能一样, 但是会在点击的时候自动追加和移除一个class,那就是active, 可以通过属性activeClassName修改
.active {
background-color: skyblue;
}
就是一个这样的效果
BrowserRouter+NavLink+Switch+Route
主要说一下Switch的用法的作用
import {Link, BrowserRouter, Route, NavLink, Switch} from 'react-router-dom'
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={About}/>
</Switch>
在注册路由时可以使用Switch包裹, 如果不使用, 那么路由匹配遇到相同的, 还会继续往下匹配,并且全部展示
不包裹VS包裹
包裹后, 遇到第一个匹配的路由,就会展示并返回, 不往下继续匹配
样式丢失问题解决[扩展]
index.html
- 在引用样式的时候写%PUBLIC_URL%
- 使用绝对路径
- 使用HashRouter[基本不用]
模糊匹配与精准匹配
默认采用模糊匹配
路由中包含传递的值,即可展示
还是可以展示的,但是路径已经变成了/home/a/b
使用exact={true}可以开启精准匹配
开启精准匹配后再次访问, 就没有展示了
BrowserRouter+NavLink+Switch+Route+Redirect
import {Link, BrowserRouter, Route, NavLink, Switch, Redirect} from 'react-router-dom'
import React, {Component} from 'react';
import {Link, BrowserRouter, Route, NavLink, Switch, Redirect} from 'react-router-dom'
import About from "./components/About";
import Home from "./components/Home";
import './App.css'
class App extends Component {
render() {
return (
// 需要在最外面包裹一个路由管理器 也可以包在index.js的app组件外面
<BrowserRouter>
<div style={{textAlign: 'center'}}>
<div>
{/*定义导航连接*/}
<NavLink to="/home">Home</NavLink>
<br/>
<NavLink to="/about">About</NavLink>
</div>
<div>
{/*注册路由*/}
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/home" />
</Switch>
</div>
</div>
</BrowserRouter>
);
}
}
export default App;
Redirect, 就是重定向的意思, 用于路由中没有匹配到路径的情况, 就会走Redirect重定向到指定路径
输入
默认会中定向到home
嵌套路由使用
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from "react-router-dom";
import News from "../../pages/News";
import Messages from "../../pages/Messages";
class Index extends Component {
render() {
return (
<div>
<h2>this is home...</h2>
<div>
<h4>导航</h4>
<NavLink to="/home/news">News</NavLink>
<br/>
<NavLink to="/home/messages">Messages</NavLink>
</div>
<div style={{textAlign: 'center'}}>
<h4>内容</h4>
<Route path="/home/news" component={News}/>
<Route path="/home/messages" component={Messages}/>
</div>
</div>
);
}
}
export default Index;
在Home组件中继续使用NavLink+Route注册路由, 但是需要携带前缀, 并且在外部不能开启精准模式,不然会造成匹配不到的情况,二级路由也可以使用Redirect实现默认选中
路由组件传递参数[params]
import React, {Component} from 'react';
import {Link, NavLink, Route} from "react-router-dom";
import Detail from "./Detail";
class Index extends Component {
state = {
items: [
{id: '1', name: 'React'},
{id: '2', name: 'Vue'},
{id: '3', name: 'Ts'}
]
}
render() {
const {items} = this.state
return (
<div>
<ul>
{
items.map(item => {
return (
<li key={item.id}>
{/* 向路由组件传递params参数 */}
<Link to={`/home/messages/detail/${item.id}/${item.name}`}>{item.name}</Link>
</li>
)
})
}
</ul>
<hr/>
{/*接收params参数*/}
<Route path='/home/messages/detail/:id/:title' component={Detail} />
</div>
);
}
}
export default Index;
import React, {Component} from 'react';
const data = [
{id: '1', content: 'this is React'},
{id: '2', content: 'this is Vue'},
{id: '3', content: 'this is Ts'}
]
class Index extends Component {
render() {
const {id, title} = this.props.match.params
const item = data.filter(x=>x.id===id)[0]
return (
<div>
<div>id:{item.id}</div>
<div>name:{title}</div>
<div>content:{item.content}</div>
</div>
);
}
}
export default Index;
通过路径参数传递
路由组件传递参数[search]
{/* 向路由组件传递search参数 */}
<Link to={`/home/messages/detail?id=${item.id}&title=${item.name}`}>{item.name}</Link>
{/*接收search参数 不需要*/}
<Route path='/home/messages/detail' component={Detail}/>
import React, {Component} from 'react';
const data = [
{id: '1', content: 'this is React'},
{id: '2', content: 'this is Vue'},
{id: '3', content: 'this is Ts'}
]
class Index extends Component {
render() {
// 接收Params参数
// const {id, title} = this.props.match.params
const {id,title} = this.getSearch()
const item = data.filter(x=>x.id===id)[0]
return (
<div>
<div>id:{item.id}</div>
<div>name:{title}</div>
<div>content:{item.content}</div>
</div>
);
}
// 获取search参数
getSearch = () => {
let search = this.props.location.search
search = search.substring(1);
let conditions = search.split("&")
let obj = {}
conditions.map(condition => {
const kv = condition.split("=")
obj[kv[0]] = kv[1]
})
return obj
}
}
export default Index;
在这里 我是自己实现了参数的解析, 也可以使用querystring的方法, 当热这个库在React18之后已经被弃用了, 本来我也想试一下的,但是发现不行
调用直接报错
应该是已经没有依赖了, 可以自己安装一下, 我就不安装了
路由组件传递参数[state(和组件的state没有关系)]
{/* 向路由组件传递state参数[和组件的state没有关系] */}
<Link to={{pathname:'/home/messages/detail',state:{id:item.id,title:item.name}}}>{item.name}</Link>
{/*接收state参数 不需要*/}
<Route path='/home/messages/detail' component={Detail}/>
import React, {Component} from 'react';
const data = [
{id: '1', content: 'this is React'},
{id: '2', content: 'this is Vue'},
{id: '3', content: 'this is Ts'}
]
class Index extends Component {
render() {
// 接收Params参数
// const {id, title} = this.props.match.params
// 接受Search参数
// const {id,title} = this.getSearch()
// 接受state参数
const {id, title} = this.props.location.state
const item = data.filter(x=>x.id===id)[0]
return (
<div>
<div>id:{item.id}</div>
<div>name:{title}</div>
<div>content:{item.content}</div>
</div>
);
}
// 获取search参数
getSearch = () => {
let search = this.props.location.search
search = search.substring(1);
let conditions = search.split("&")
let obj = {}
conditions.map(condition => {
const kv = condition.split("=")
obj[kv[0]] = kv[1]
})
return obj
}
}
export default Index;
可以直接从location.state上获取, 并且不会在地址栏上显示
replace与push
默认使用push,采用压栈方式存储历史记录, 可以通过back,go来完成前进或者后退
可以修改为replace替换, 默认会替换栈顶部的历史记录, 所以不会留下痕迹, 也就不能通过back,go完成前进和后退
修改方式为, 增加replace属性
编程试路由导航
<Link replace to={{
pathname: '/home/messages/detail',
state: {id: item.id, title: item.name}
}}>{item.name}</Link>
<button style={{marginLeft: '5px'}} onClick={event => {
this.show(item.id, item.name, 'push')
}}>push</button>
<button style={{marginLeft: '5px'}} onClick={event => {
this.show(item.id, item.name, 'replace')
}}>replace</button>
<Route path='/home/messages/detail/:id/:title' component={Detail}/>
show = (id, title, type) => {
// replace | push 路由跳转
this.props.history[type](`/home/messages/detail/${id}/${title}`)
}
通过props对象上的history对象调用方法实现编程式路由跳转
这个案例是用params参数的方式,如果是search方式就自己改一下问号, 如果是state方式, 就把对象放入参数的第二个参数,第一个是URL, 第二个就是state
路由组件与一般组件
# 直接使用定义的组件 就是一般组件 渲染时props中不会有默认路由组件的三大对象
<Header />
# 通过路由跳转的组件 就是路由组件 渲染时props中会携带 history location match 三大对象
<Route path="/home" component={Home}/>
如果想要在一般组件中使用路由组件的三大对象, 那么就需要withRouter函数
withRouter
import React, {Component} from 'react';
import {withRouter} from "react-router-dom";
class Index extends Component {
render() {
console.log(this)
return (
<div>
<h2>this is Header</h2>
</div>
);
}
}
export default withRouter(Index);
这样就可以获取到三大对象了
路由默认入参对象总结
对象 | 函数/属性 | 作用 |
history | go(n) | 传入一个number数值,1代表前进一步,-1代表后退一步, 2代表前进两步 |
goBack() | 后退一步 | |
goForward() | 前进一步 | |
push(uri, state) | push方式跳转路由, 第一个参数是路由地址, 第二个是state对象 | |
replace(uri,state) | replace方式跳转路由, 第一个参数是路由地址, 第二个是state对象 | |
location | pathname | 路由地址 |
search | search方式传参的获取位置 | |
state | state方式传参的获取位置 | |
match | params | params方式传参的获取位置 |
path | 路由地址 | |
url | 路由地址 |
BrowserRouter和HashRouter的区别
- 底层原理不一样
- BrowserRouter使用的是H5的History API不兼容IE9及其以下的版本
- HashRouter使用的是URL的哈希值
- URL的表现形式不一样
- BrowserRouter的路径中没有#, 例如http://localhost:3000/home
- HashRouter的路径包含#, 例如http://localhost:3000/#/home
- 刷新后对路由state参数的影响
- BrowserRouter没有任何影响, 应为state保存在History对象中
- HashRouter刷新会导致路由state参数的丢失
- 扩展: HashRouter可以用于解决一些路劲错误相关的问题
所有评论(0)