React Router包含了四个包:
包名 | 描述 |
---|---|
react-router | React Router 核心api |
react-router-dom | React Router的DOM绑定,在浏览器中运行不需要额外安装 react-router |
react-router-native | React Native中使用,而实际的应用中,其实不会使用这个。 |
react-router-config | 静态路由的配置 |
主要使用 react-router-dom
React Router 甚至大部分的前端路由都是依赖于 history.js 的,它是一个独立的第三方js库。可以用来兼容在不同浏览器、不同环境下对历史记录的管理,拥有统一的 API。
//默认使用的是history模式
import {
BrowserRouter as Router} from 'react-router-dom';
//更改为hash模式
import {
HashRouter as Router} from 'react-router-dom';
hash
来存储在不同状态下的 history
信息,对应 createHashHistory
,通过检测 location.hash
的值的变化,使用 location.replace
方法来实现 url 跳转。通过注册监听 window
对象上的 hashChange
事件来监听路由的变化,实现历史记录的回退。createBrowserHistory
,使用包括 pushState
, replaceState
方法来进行跳转。通过注册监听 window
对象上的 popstate
事件来监听路由的变化,实现历史记录的回退。createMemoryHistory
。直接在内存里 push
和 pop
状态。在终端中执行下面的命令,安装 react-router-dom,-S 表示在生产环境使用
yarn add react-router-dom -S
a标签
,相当于vue中的 component 属性
,也可以使用 render() 函数
,使用 component 的方式是不能直接在组件上添加属性的,可以使用 render() 函数,这个常用于页面组件级别的权限管理;props参数
,通过 props.match.params 可以获取 url的动态参数;
标签中,exact
属性表示严格匹配,为 false 时表示模糊匹配;
标签,通过设置 from 和 to 属性值,进行路由跳转;
标签的作用是排他性,从上往下按顺序匹配路由,匹配成功后,就不再往下找了;动态参数(如 /:id)
和 params 参数(如 /name=zz&age=18)
两种方式,可以通过 props
属性来获取传递的内容;多视图概念
,如果不使用嵌套路由
,在子组件中路由使用方法和父组件中一致,不同的是子组件中最外层不需要再使用*
",也可以不写 path,表示全部匹配;import React, {
Component } from 'react'
import ReactDOM from 'react-dom'
import {
BrowserRouter as Router, //设置别名为 Router
Route,
Link,
Redirect,
Switch,
useLocation
} from 'react-router-dom'
const Home = () => {
return <h1>Home page</h1>
}
const About = (props) => {
//函数组件默认接收一个 props参数
//以下三种方式都可以获取 url中的参数
let query1=props.location.search;
let query2=useLocation().search;
let query3=window.location.search;
//打印结果都为 ?city=beijing&code=18
console.log(query1,query2,query3);
//通过 new URLSearchParams()获取参数的值
let query=new URLSearchParams(useLocation().search).get('city')
return <h1>About page,city:{
query}</h1>
}
const Login = () => {
return <h1>Login page</h1>
}
class Page extends Component {
render() {
return (
<Router>
{
/* Link 默认会被解析成 a标签 */}
<Link to="/home">首页</Link>
<Link to="/about/?city=beijing&code=18">关于我们</Link>
<Link to="/product/34">产品</Link>
<Link to="/login">登录</Link>
<hr />
{
/* Switch 的作用是从上往下匹配路由,匹配成功后,就不再往下找了 */}
<Switch>
{
/* 渲染组件可以使用 component,也可以使用 render()函数 */}
<Route path="/home" component={
Home}></Route>
<Route path="/about" component={
About}></Route>
<Route path="/login" component={
Login}></Route>
<Route path="/product/:id" render={
(props)=>{
//默认接收一个props参数,通过 props.match.params获取 url的动态参数
return <h1>Product page,id:{
props.match.params.id}</h1>
}}></Route>
{
/* exact 表示精确匹配 */}
<Redirect exact from="/" to="/home"></Redirect>
<Route path="*" render={
() => {
return <div>404 page not found...</div>
}}></Route>
</Switch>
</Router>
)
}
}
ReactDOM.render(
<Page/>,
document.getElementById('root')
);
在 vue 中,我们可以使用 router.beforeEach
做路由的权限验证,在 react 中,可以通过 render() 函数做逻辑处理
,来实现这个功能。
例如,当用户是未登录状态时,可以访问首页内容,当访问用户管理页面时,跳转至登陆页,代码如下:
import React, {
Component } from 'react'
import ReactDOM from 'react-dom'
import {
BrowserRouter as Router, Route, Link } from 'react-router-dom'
const Home = () => <h1>Home page</h1>
const Login = () => <h1>Login page</h1>
const User = () => <h1>user page</h1>
export default class Page extends Component {
constructor() {
super();
//routers 相当于是路由配置文件
this.routers = [
{
path: "/home", component: Home, auth: false},
{
path: "/login", component: Login, auth: false},
{
path: "/user", component: User, auth: true}
]
}
render() {
return (
<Router>
<Link to="/home">首页</Link>
<Link to="/user">用户管理</Link>
{
this.routers.map((item, index) => {
return <Route key={
index} path={
item.path} render={
() => {
//判断当前跳转的路由是否需要进行验证
return item.auth ? <Login></Login> : <item.component></item.component>
}}>
</Route>
})
}
</Router>
)
}
}
ReactDOM.render(
<Page/>,
document.getElementById('root')
);
通过设置 react-router-dom 中自带的
标签的 activeClassName
属性,可以动态设置当前页面路由标签的选中样式;也可以通过下面自定义导航
的方式实现当前页面路由标签的选中样式。
<NavLink activeClassName="active" to="/home">首页NavLink>
<NavLink activeClassName="active" to="/about">关于我们NavLink>
在 react-router-dom 中, 标签默认会被解析成 a 标签,如果想以
标签或者别的标签展示,就可以通过自定义导航来实现;自定义导航也可以设置当前页面路由标签的选中样式。设置自定义导航有以下几种方式:
创建自定义组件,通过将标签包裹,完成自定义导航。
const CustomLink = (prop) => {
return (
<li>
<Link to={
prop.path}>{
prop.name}</Link>
</li>
)
}
<CustomLink path="/home" name="首页"></CustomLink>
通过 withRouter()
高阶函数,可以拿到路由的上下文信息,并对当前组件功能做增强,这种方式用起来更灵活,藕合性低。
通过 this.props.history.push()
可以实现编程式导航页面跳转。
/* About.jsx */
import React, {
Component } from 'react'
import {
withRouter } from 'react-router-dom'
class About extends Component {
handleClick = () => {
//编程式导航
this.props.history.push(this.props.path)
}
render() {
return (
<li className={
this.props.path === this.props.location.pathname ? 'active':''} onClick={
this.handleClick}>
关于我们
</li>
)
}
}
export default withRouter(About)
在入口文件中引用:
import React from 'react'
import ReactDOM from 'react-dom'
import {
BrowserRouter as Router } from 'react-router-dom'
import About from './About'
const Index=()=>{
return (
<Router>
<About path="/about"></About>
</Router>
)
}
ReactDOM.render(
<Index/>,
document.getElementById('root')
);
注意:
children
属性,可以进行逻辑操作,将标签包裹,以及用来判断当前标签是否被选中。<Route path="/product" children={
(props)=>{
return <Link className={
props.match?'active':''} to="/product">产品</Link>
}}></Route>
自定义导航三种方式汇总:
import React, {
Component } from 'react'
import ReactDOM from 'react-dom'
import {
BrowserRouter as Router,Route,Link,NavLink} from 'react-router-dom'
import About from './About' //About.jsx 文件同上面3.4.2中
const CustomLink = (props) => {
return <li><Link to={
props.path}>{
props.name}</Link></li>
}
class Page extends Component {
render() {
return (
<Router>
<ul>
//方式一
<CustomLink path="/home" name="首页"></CustomLink>
//react-router-dom 自带标签
<NavLink activeClassName="active" to="/login">登录</NavLink>
//方式二
<About path="/about"></About>
//方式三
<Route path="/product" children={
(props)=>{
return <Link className={
props.match?'active':''} to="/product">产品</Link>
}}></Route>
</ul><hr/>
<Route exact path="/home"><h1>首页</h1></Route>
<Route exact path="/login"><h1>登录</h1></Route>
<Route exact path="/about"><h1>关于我们</h1></Route>
<Route exact path="/product"><h1>产品</h1></Route>
</Router>
)
}
}
ReactDOM.render(
<Page/>,
document.getElementById('root')
);
页面效果如下,点击上面的导航,在下方显示对应内容,并且该导航标签上增加 active 的样式(这里设置选中导航字体为红色)。