安装
// 安装 React 路由组件库
yarn add react-router-dom
一级路由
src 目录,UI库用的 bootstrap
// index.js
import React from "react"
import ReactDOM from "react-dom"
import {BrowserRouter} from "react-router-dom"
import App from "./App"
const element = <BrowserRouter><App/></BrowserRouter>
ReactDOM.render(element,document.getElementById("root"));
// App.js
import React, { Component } from 'react'
import Header from "./components/Header"
import MyRouter from "./components/MyRouter"
import MyRender from "./components/MyRender"
export default class App extends Component {
render() {
return (
<div className="container">
<Header/>
<MyRouter/>
<MyRender/>
</div>
)
}
}
// Header
import React, { Component } from 'react'
export default class Header extends Component {
render() {
return (
<div className="page-header">
<h1>React 小知识 - 路由组件 <small>react-router-dom</small></h1>
</div>
)
}
}
// MyRouter
import React, { Component } from 'react'
import {NavLink} from "react-router-dom"
export default class MyRouter extends Component {
render() {
return (
<div>
<NavLink className="btn btn-primary" to="/home">Home</NavLink>
<NavLink className="btn btn-primary" to="/about">About</NavLink>
</div>
)
}
}
// MyRender
import React, { Component } from 'react'
import {Route,Switch,Redirect} from "react-router-dom"
import Home from "../../pages/Home"
import About from "../../pages/About"
export default class MyRender extends Component {
render() {
return (
<Switch>
<Route path="/home" component={Home}></Route>
<Route path="/about" component={About}></Route>
<Redirect to="/about" />
</Switch>
)
}
}
npm start,大概样子应该如下
敲黑板:
// MyRouter
import {Route,Switch,Redirect} from "react-router-dom"
在 MyRouter 组件中的 Route 是用来注册路由的组件,使用了 Switch 则是匹配单个组件,下图是没有使用
<div>
<Route path="/home" component={Home}></Route>
<Route path="/about" component={About}></Route>
<Route path="/about" component={Home}></Route>
<Redirect to="/about" />
</div>
路径相同,但是匹配了两个组件,这个时候可以用 Switch 只匹配第一个,而不继续匹配下去
// MyRouter
<Switch>
<Route path="/home" component={Home}></Route>
<Route path="/about" component={About}></Route>
<Route path="/about" component={Home}></Route>
<Redirect to="/about" />
</Switch>
Redirect 则是路由重定向,避免首次加载,内容为空。可以将其的修改为下图,再查看页面变化
<Redirect to="/home" />
这里注意一下,NavLink 和 Link 的区别,简书-潇湘轮回
就个人总结而言,主要是 NavLink 支持激活后的样式,添加 activeClassName = "样式名"
由于这里的 active 类名和 bootstrap 重名了,可以手动替换其他自定义类名
<NavLink activeClassName="active" className="btn btn-primary" to="/home">Home</NavLink>
一个小技巧,可以封装一个自定义 NavLink 组件,{...this.props} 将会结构 props
// MyNavLink
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="active" className="btn btn-primary" {...this.props} />
)
}
}
改造一下 MyRouter 组件
// MyRouter
import React, { Component } from 'react'
import MyNavLink from "../MyNavLink"
export default class MyRouter extends Component {
render() {
return (
<div>
<MyNavLink to="/home" children="Home" />
<MyNavLink to="/about" children="About" />
</div>
)
}
}
避免重复添加 activeClassName 属性,其中 children 的值,看如下
<MyNavLink to="/home" children="Home" />
// 上下其实是相同的
<MyNavLink to="/home">Home</MyNavLink>
// 注意看 MyNavLink 中 console.log 的值,就会理解 children 的属性用法
嵌套路由
src 目录
// Message
import React, { Component } from 'react'
export default class Message extends Component {
render() {
return (
<div>
This page is Message
</div>
)
}
}
// News
import React, { Component } from 'react'
export default class News extends Component {
render() {
return (
<div>
This page is News
</div>
)
}
}
接下来,改造一下 Home 组件内容
// Home
import React, { Component } from 'react'
import {Switch,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>
<h2>This page is Home</h2>
<div>
<MyNavLink to="/home/message" children="message" />
<MyNavLink to="/home/news" children="news" />
</div>
<div>
<Switch>
<Route path="/home/message" component={Message} />
<Route path="/home/news" component={News} />
<Redirect to="/home/message" />
</Switch>
</div>
</div>
)
}
}
效果图 如下
多级路由 以此类推
路由传参
src 目录下 新增 Detail 组件,一级改写 Message 组件
// Detail
import React, { Component } from 'react'
export default class Detail extends Component {
render() {
console.log(this.props);
return (
<div>
<h4>This page is detail</h4>
<div>
<p>id:xx</p>
<p>title:xxxx</p>
<p>content:xxxxxx</p>
</div>
</div>
)
}
}
// Message
import React, { Component } from 'react'
import {Link,Route} from "react-router-dom"
import Detail from "../../../components/Detail"
export default class Message extends Component {
render() {
return (
<div>
<h3>This page is Message</h3>
<div>
<Link className="btn btn-info" to="/home/message/detail">detail-01</Link>
<Link className="btn btn-info" to="/home/message/detail">detail-02</Link>
<Link className="btn btn-info" to="/home/message/detail">detail-03</Link>
</div>
<Route path="/home/message/detail" component={Detail} />
</div>
)
}
}
效果图如下
params 传参
修改 Message 组件中的部分内容
// Message
<div>
<Link className="btn btn-info" to="/home/message/detail/01">detail-01</Link>
<Link className="btn btn-info" to="/home/message/detail/02">detail-02</Link>
<Link className="btn btn-info" to="/home/message/detail/03">detail-03</Link>
</div>
<Route path="/home/message/detail/:id" component={Detail} />
点击 detail-01 按钮,注意红框中的内容
点击红框中的 match,会发现 这里的 params 的id 01 就是传过来的参数,接下去再传一个 title
修改 Message 组件中的部分内容
// Message
<div>
<Link className="btn btn-info" to="/home/message/detail/01/Hello React">detail-01</Link>
<Link className="btn btn-info" to="/home/message/detail/02/Hello Vue">detail-02</Link>
<Link className="btn btn-info" to="/home/message/detail/03/Hello Angular">detail-03</Link>
</div>
<Route path="/home/message/detail/:id/:title" component={Detail} />
点击红框中的 match,会发现 这里的 params 的id 01 就是传过来的参数,接下去再传一个 title
这个就显而易见了,接下去让其内容在 Detail 组件中显示
首先更改一下 Detail 组件
// Detail
import React, { Component } from 'react'
const data = [
{
id:"01",
content:"你好 React"
},
{
id:"02",
content:"你好 Vue"
},
{
id:"03",
content:"你好 Angular"
}
]
export default class Detail extends Component {
render() {
console.log(this.props);
const {id,title} = this.props.match.params;
const resultContent = data.find((item,index,arr) => {
return item.id === id;
}); // 数组的 find 函数 查找符合条件的对象并返回
return (
<div>
<h4>This page is detail</h4>
<div>
<p>id:{id}</p>
<p>title:{title}</p>
<p>content:{resultContent.content}</p>
</div>
</div>
)
}
}
效果图如下
query 传参(search)
修改 Message 组件中的内容,记得 Detail 组件中的内容也需要修改一下,避免报错
// Message
import React, { Component } from 'react'
import {Link,Route} from "react-router-dom"
import Detail from "../../../components/Detail"
export default class Message extends Component {
render() {
return (
<div>
<h3>This page is Message</h3>
<div>
<Link className="btn btn-info" to="/home/message/detail/?id=01&title=Hello React">detail-01</Link>
<Link className="btn btn-info" to="/home/message/detail/?id=02&title=Hello Vue">detail-02</Link>
<Link className="btn btn-info" to="/home/message/detail/?id=03&title=Hello Angular">detail-03</Link>
</div>
<Route path="/home/message/detail" component={Detail} />
</div>
)
}
}
点击 detail-01 按钮
敲黑板: 注意这个 search 值,不能直接使用,引入一下 querystring 库,React 已经帮忙准备好了,修改 Detail 组件
// Detail
import React, { Component } from 'react'
import qs from "querystring"
const data = [
{
id:"01",
content:"你好 React"
},
{
id:"02",
content:"你好 Vue"
},
{
id:"03",
content:"你好 Angular"
}
]
export default class Detail extends Component {
render() {
console.log(this.props);
const {id,title} = qs.parse(this.props.location.search.slice(1));// 问号不需要,截取问号后面的内容
const resultContent = data.find((item,index,arr) => {
return item.id === id;
}); // 数组的 find 函数 查找符合条件的对象并返回
return (
<div>
<h4>This page is detail</h4>
<div>
<p>id:{id}</p>
<p>title:{title}</p>
<p>content:{resultContent.content}</p>
</div>
</div>
)
}
}
效果图 如下
state 传参
修改 Message 组件中的内容,记得 Detail 组件中的内容也需要修改一下,避免报错
// Message
import React, { Component } from 'react'
import {Link,Route} from "react-router-dom"
import Detail from "../../../components/Detail"
export default class Message extends Component {
render() {
return (
<div>
<h3>This page is Message</h3>
<div>
<Link className="btn btn-info" to={{pathname:"/home/message/detail",state:{id:"01",title:"Hello React"}}}>detail-01</Link>
<Link className="btn btn-info" to={{pathname:"/home/message/detail",state:{id:"02",title:"Hello Vue"}}}>detail-02</Link>
<Link className="btn btn-info" to={{pathname:"/home/message/detail",state:{id:"03",title:"Hello Angular"}}}>detail-03</Link>
</div>
<Route path="/home/message/detail" component={Detail} />
</div>
)
}
}
注意控制台的 state
Detail 组件内容
// Detail
import React, { Component } from 'react'
const data = [
{
id:"01",
content:"你好 React"
},
{
id:"02",
content:"你好 Vue"
},
{
id:"03",
content:"你好 Angular"
}
]
export default class Detail extends Component {
render() {
console.log(this.props);
const {id,title} = this.props.location.state;
const resultContent = data.find((item,index,arr) => {
return item.id === id;
}); // 数组的 find 函数 查找符合条件的对象并返回
return (
<div>
<h4>This page is detail</h4>
<div>
<p>id:{id}</p>
<p>title:{title}</p>
<p>content:{resultContent.content}</p>
</div>
</div>
)
}
}
效果图 如下
至此三种路由传参都解释完
这里会发现,路由传参中,Home和message按钮的颜色变成了 深蓝色,并不是红色,这里涉及到样式丢失
修改 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<!-- <link rel="stylesheet" href="./index.css"> -->
<link rel="stylesheet" href="%PUBLIC_URL%/index.css"> <!-- 这里与注释的内容对比 -->
</head>
<body>
<div id="root"></div>
</body>
</html>
编程式路由跳转
注意下图红框内容
修改 Detail 组件内容
// Detail
import React, { Component } from 'react'
const data = [
{
id:"01",
content:"你好 React"
},
{
id:"02",
content:"你好 Vue"
},
{
id:"03",
content:"你好 Angular"
}
]
export default class Detail extends Component {
render() {
console.log(this.props);
const {id,title} = this.props.location.state;
const resultContent = data.find((item,index,arr) => {
return item.id === id;
}); // 数组的 find 函数 查找符合条件的对象并返回
return (
<div>
<h4>This page is detail</h4>
<div>
<p>id:{id}</p>
<p>title:{title}</p>
<p>content:{resultContent.content}</p>
<div>
<button className="btn btn-success">前进</button>
<button className="btn btn-success">后退</button>
<button className="btn btn-success">跳转</button>
</div>
</div>
</div>
)
}
}
编写前进,后退,跳转事件 并绑定事件
// 前进
handleGoForward = () => {
this.props.history.goForward();
}
// 后退
handleGoBack = () => {
this.props.history.goBack();
}
// 跳转
handleGo = () => {
this.props.history.go(-2);
}
// Message
<p>id:{id}</p>
<p>title:{title}</p>
<p>content:{resultContent.content}</p>
<div>
<button className="btn btn-success" onClick={this.handleGoForward}>前进</button>
<button className="btn btn-success" onClick={this.handleGoBack}>后退</button>
<button className="btn btn-success" onClick={this.handleGo}>跳转</button>
</div>
普通组件 转换为 路由组件
首先修改一下 Header 组件
// Header
import React, { Component } from 'react'
class Header extends Component {
// 前进
handleGoForward = () => {
this.props.history.goForward();
}
// 后退
handleGoBack = () => {
this.props.history.goBack();
}
// 跳转
handleGo = () => {
this.props.history.go(-2);
}
handleNav = () => {
this.props.history.push("/home/message/detail",{id:"02",title:"我是迪迦,我要拯救世界"});
}
render() {
return (
<div className="page-header">
<h1>React 小知识 - 路由组件 <small>react-router-dom</small></h1>
<div>
<button className="btn btn-success" onClick={this.handleGoForward}>前进</button>
<button className="btn btn-success" onClick={this.handleGoBack}>后退</button>
<button className="btn btn-success" onClick={this.handleGo}>跳转</button>
<button className="btn btn-success" onClick={this.handleNav}>编程导航</button>
</div>
</div>
)
}
}
export default Header
如下图
会发现点击按钮直接报错,那是因为这个 Header 组件的 props 并没有提供 路由的 api,所以无法正常跳转
直接请出 withRouter
修改 Header 组件部分内容
// Header
import React, { Component } from 'react'
import {withRouter} from "react-router-dom"
class Header extends Component {
// 前进
handleGoForward = () => {
this.props.history.goForward();
} ...
export default withRouter(Header)
顺便提一嘴,路由跳转有两种,默认 push 会记录导航历史,replace 则不会
以上皆为看网上教学视频,个人总结,有问题别问我,我回答不上来