React 路由介绍(路由跳转、react-router-dom、路由传递参数)(七)

React 路由介绍(七)

React 官网链接:

接着上节 React ajax 发送请求(六)

前言

在我们实际开发的时候,React 应用其实是一个单页Web应用(single page web application,SPA),SPA应用的特点如下:

  • 单页Web应用,整个应用只有一个完整的页面
  • 点击页面中的链接 不会刷新整个页面,只会做页面的 局部更新
  • 数据都需要通过 ajax 请求获取,并在前端异步展现

在原生的 html 中,跳转页面靠 标签来进行页面的跳转,而在 React 中靠 路由链接 实现组件的切换,从而实现页面的局部更新,所以需要编写 路由链接,这里会涉及一个概念 路由

路由

1. 什么是路由

  • 一个路由就是一个映射关系 (key:value)
  • key为路径,value可能是 functioncomponent

2. 路由分类

后端路由:

  • 理解: value 是 function,用来处理客户端提交的请求

  • 注册路由:

    router.get(path, function(req, res))
    
  • 工作过程:当 node 接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据

前端路由:

  • 浏览器端路由,value 是 component,用于展示页面内容

  • 注册路由

     <Route path="/test" component={Test}>
    
  • 工作过程:当浏览器的path变为 /test 时,当前路由组件就会变为 Test组件

react-router-dom

在 React 实现 SPA 应用的时候就不得不介绍一个插件库 react-router-dom,基于react的项目基本都会用到此库

1、安装

因为其是一个插件库,直接安装这个插件即可, 如果没有环境,请查看 node 介绍、安装、升级(node npm)

npm i react-router-dom

2、基本知识介绍

2.1 模糊匹配 与 精准匹配
  • 模糊匹配: 路由匹配时,以 符合的 path 开头就算匹配成功,匹配成功就加载对应组件
  • 精准匹配: 路由匹配时,path要完全符合,就算匹配成功

example:

1)定义了一个链接 , 去往的 path 定义为 /home/a 
2)声明了一个路由 , 指定path 为 /home 时,去往 home 组件

- 如果是模糊匹配:点击该链接,会切换至 home 组件(前缀相同)
- 如果是精准匹配:点击该链接,不会切换至 home 组件(路径需要完全一样),如果又声明了一个路由 指定path 为 /home/a 时,去往 a 组件 , 点击该链接,会切换至 a组件
2.2 路由规则(栈)

因为是SPA应用,仅仅涉及一个页面,通过路由来实现局部刷新,声明了很多路由Route与对应的路由跳转Link

我们在浏览器操作时候,可通过点击 路由跳转Link 实现路由跳转,也可点击 回退按钮 / 前进按钮 实现路由切换,路由的具体规则如下:

路由总体来说是一个栈的结构,点击新路由即将该路由入栈,入栈有两种方式:

  • 追加(PUSH):即不移除当前栈顶,下面讲解的Route 路由切换默认是这种方式
  • 替代(REPLACE):即将新入栈的路由替代当前栈顶

两种方式直观的区间就是:

  • 追加(PUSH):点击多个链接使路由入栈,然后 点击 回退按钮 / 前进按钮 可实现路由切换。
  • 替代(REPLACE):点击多个链接使路由入栈,然后 点击 回退按钮 / 前进按钮 ,之前入栈的路由不会显示

图示:

追加 的方式:先点击了 About 使 /about 路由 入栈,后点击了 Home 使 /home 路由入栈,那么在 /about 可以点击 前进按钮 进入到 /home 路由,在 /home 可以点击 后退按钮 进入到 /about路由,正常进行路由切换

请添加图片描述

替换 的方式:先点击了 About 使 /about 路由 入栈,后点击了 Home 使 /home 路由入栈,那么在 /about 可以点击 前进/后退按钮 只会停留在 /about 路由,同理,在 /home 可以点击 前进/后退按钮 只会停留在 /home路由

请添加图片描述

2.3 路由组件与普通组件

路由组件与普通组件的实现基本相同,都是编写jsx文件,但是在具体的使用有一些差距:

example:

  • 普通组件的使用:(<App/>)
//引入App 组件
import App from './App'
ReactDOM.render(
	<App/> //  使用 普通组件
	document.getElementById('root')
)
  • 路由组件的使用:(Home)
import Home from './Home' // 引用Home组件
return (
    <div>
      <h1>react路由基本使用</h1>
      <HashRouter>
          <Link to="/home">评论</Link> 
   		 // 使用路由组件 Home
          <Route path="/home" component={Home} /> 
        </Switch>
      </HashRouter>
    </div>
)

说明:

普通组件与路由组件的一个很重要的区别在于 props (即传入的参数)的不同:

  • 普通组件:若在使用的时候,不传入参数,那props即为空

请添加图片描述

  • 路由组件:即使在使用的时候,不传入参数,props也会有相应的东西(具体字段后面讲 路由组件传递参数 的时候说明)

请添加图片描述

如果想要普通组件 变成 路由组件 ,具备props,可以在 组件 export 的时候,利用 <withRouter> 包裹即可

import React, { Component } from 'react'
// 导入 withRouter
import {withRouter} from 'react-router-dom'
// 本来式一个普通组件
class Header extends Component {

	back = ()=>{
		this.props.history.goBack()
	}

	forward = ()=>{
		this.props.history.goForward()
	}

	go = ()=>{
		this.props.history.go(-2)
	}

	render() {
		console.log('Header组件收到的props是',this.props);
		return (
			<div className="page-header">
				<h2>React Router Demo</h2>
				<button onClick={this.back}>回退</button>&nbsp;
				<button onClick={this.forward}>前进</button>&nbsp;
				<button onClick={this.go}>go</button>
			</div>
		)
	}
}
// 用 withRouter 包裹进行 export 即可成为 路由组件
export default withRouter(Header)

3、API介绍与使用

react-router-dom 中内置了很多组件,如下:

  • Router 组件
    • <BrowserRouter>
    • <HashRouter>
  • Route 组件
    • <Route>
  • Link 组件
    • <Link>
    • <NavLink>
  • Switch 组件
    • <Switch>
  • Redirect 组件
    • <Redirect>

下面一一介绍一下

3.1 Router 组件 (其用于整个应用,一般一个 React 应用仅需使用一次)

常见的有两种 :

  • <BrowserRouter>
  • <HashRouter>

组件一般放在最顶层所有组件之外,这样能确保内部组件使用 Link 做路由跳转时不出错

这两个组件的底层区别在于使用原理不同,直观区别是其路径前缀会不会有 # 号出现,常用的话,一般 BrowserRouter 使用的多一些

  • BrowserRouter :使用 H5 的 history.pushState() API 实现,原理即监听 window 的 popstate 事件,路径不会带 # 号,例如 :
    • 启动路径为 localhost:3000 ,若 path 为 /about ,则浏览器地址为 localhost:3000/about
  • HashRouter :使用 URL 的 hash 实现,原理即监听 window 的 hashchange 事件,路径会带 # 号,例如 :
    • 启动路径为 localhost:3000 ,若 path 为 /about ,则浏览器地址为 localhost:3000/#/about

使用举例:(index.js

//引入react核心库
import React from 'react'
//引入ReactDOM
import ReactDOM from 'react-dom'
// BrowserRouter
import {BrowserRouter , HashRouter}  from 'react-router-dom'
//引入App
import App from './App'

ReactDOM.render(
  <BrowserRouter>
	<App/>
  </BrowserRouter>,
  document.getElementById('root')
)

// 或者
ReactDOM.render(
  <HashRouter>
    <App/>
  </HashRouter>,
  document.getElementById('root')
)

图示:

BrowserRouter:

请添加图片描述

HashRouter:

请添加图片描述

3.2 Link 组件 :编写路由链接,指定路由导航

常见的有两种 :

  • <Link > 可配置字段如下:(常用的已加粗显示)
    • to=“”:具体的path
    • replace:将路由规则改为 替代模式(默认是追加),取值为 boolean 或者 undefined
    • innerRef:引用的标签,类似a标签的ref,取值为 React.Ref<HTMLAnchorElement> 或者 undefined;
  • <NavLink> 可配置字段如下:(常用的已加粗显示)
    • to:具体的path
    • activeClassName:高亮样式类名,取值为 string 或者 undefined
    • activeStyle:高亮的样式,取值为 React.CSSProperties 或者 undefined
    • exact:是否精准匹配,取值为 boolean 或者 undefined
    • strict:是否开启严格模式 ,取值为 boolean 或者 undefined
    • isActive:当前导航是否是这个 取值为 Location 或者 boolean
    • location:当前导航的具体位置,取值为 H.Location 或者 undefined
    • className:如果当前导航是这个,为类名称,取值为 string 或者 undefined;
    • style:取值为 React.CSSProperties 或者 undefined
    • sensitive:取值为 boolean 或者 undefined;

共同点:

  • 两个组件中的 to 属性都是会渲染成 <a>href 属性

区别:

  • NavLink是一个特殊的 Link 组件,其有一些额外的字段可配置,可用于指定当前导航高亮

使用举例:(App.jsx

import React, { Component } from 'react'
import {Link, NavLink , Route} from 'react-router-dom'
import Home from './components/Home'
import About from './components/About'

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">
							{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
							<Link className="list-group-item" to="/about">About</Link>
							<Link className="list-group-item" to="/home">Home</Link>

							{/* 在React中靠路由链接实现切换组件--编写路由链接 , hhhh 是自己定义的点击的高亮样式 */}
							<NavLink activeClassName="hhhh" className="list-group-item" to="/about">About</NavLink>
							<NavLink activeClassName="hhhh" className="list-group-item" to="/home">Home</NavLink>
						</div>
					</div>
					<div className="col-xs-6">
						<div className="panel">
							<div className="panel-body">
								{/* 注册路由  /about 对应写的 About 组件,/home 对应写的 Home 组件*/}
								<Route path="/about" component={About}/>
								<Route path="/home" component={Home}/>
							</div>
						</div>
					</div>
				</div>
			</div>
		)
	}
}

说明:(定义了两个 导航栏 分别是 About,Home)

  • 如果用 Link , 点击 About / Home 切换时,切换成的当前导航并不会显示具体样式
  • 如果用 NavLink, 点击 About / Home 切换时,切换成的当前导航会显示具体样式(这里即显示的是hhh样式)
3.3 Route 组件:路径的具体匹配规则,即path与component的对应关系

这个组件主要定义具体的路由匹配规则,

  • <Route > 可配置字段如下:(常用的已加粗显示)
    • path:具体的path,与 Link 组件的 to属性值对应, 取值为 Path 或者 Path[] 或者 undefined
    • component:定义的组件,取值为 React.ComponentType<RouteComponentProps<any>> 或者 React.ComponentType<any> 或者 undefined
    • exact:是否开启精准匹配,取值为 boolean 或者 undefined
    • location: 取值为 H.Location 或者 undefined;
    • render: 取值为 ((props: RouteComponentProps) => React.ReactNode) 或者 undefined;
    • children: 取值为 ((props: RouteChildrenProps) => React.ReactNode) 或者 React.ReactNode 或者 undefined;
    • sensitive: 取值为 boolean 或者 undefined
    • strict: 取值为 boolean 或者 undefined

使用举例:(也可参照 Link 组件中的样例)

// path:link组件中to的属性值
<Route path="/xx/xx" component={组件}></Route> 

模糊匹配 与 精准匹配(默认是模糊匹配)

  • 模糊匹配 只要 link 组件中 to 的属性值,以 path 开头就算匹配成功,匹配成功就加载对应组件
  • 精准匹配 需要 link 组件中 to 的属性值 与 path 完全相同才会匹配

example:

// 默认模糊匹配,这样的话,点击Home会切换至MyHome组件
<NavLink to="/home/a/b">Home</NavLink>
<Route exact path="/home" component={MyHome}/>

// exact 确定为精准匹配,这样的话,点击Home不会切换至MyHome组件
<NavLink to="/home/a/b">Home</NavLink>
<Route exact path="/home" exact component={MyHome}/>
3.4 Switch组件:包裹多个 Route ,根据路由规则进行匹配

<Switch>组件可 包裹多个Route组件,对to的属性值进行匹配,但无论有多少个 Route 的路由规则匹配成功,都只会渲染第一个匹配的组件

example:(App.jsx

export default class App extends Component {
	render() {
		return (
			<div>
				<div className="row">
					<div className="col-xs-offset-2 col-xs-8">
						<Header/>
					</div>
				</div>
				<div className="row">
					<div className="col-xs-2 col-xs-offset-2">
						<div className="list-group">
							{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
							<NavLink to="/about">About</NavLink>
							<NavLink to="/home">Home</NavLink> 
						</div>
					</div>
					<div className="col-xs-6">
						<div className="panel">
							<div className="panel-body">
								{/* 注册路由 */}
								<Switch>
									<Route path="/about" component={About}/>
									// /home会匹配为Home组件,而不是切换为下面的 Test 组件
									<Route path="/home" component={Home}/> 
									<Route path="/home" component={Test}/>
									// 这里可以不设置path属性,将404页对应的组件放在最后位置来设置404页面                   
									<Route component={Page404} /> 
								</Switch>
							</div>
						</div>
					</div>
				</div>
			</div>
		)
	}
}
3.5 Redirect组件:路由默认跳转组件的设置

<Redirect> 用来设置默认跳转路由

example:

<div className="row">
	<div className="col-xs-2 col-xs-offset-2">
        <div className="list-group">
             {/* 在React中靠路由链接实现切换组件--编写路由链接 */}
             <NavLink to="/about">About</NavLink>
             <NavLink to="/home">Home</NavLink>
			<NavLink to="/hshshhs">Home</NavLink>
        </div>
	</div>
	<div className="col-xs-6">
		<div className="panel">
			<div className="panel-body">
			{/* 注册路由 */}
				<Switch>
					<Route path="/about" component={About}/>
					<Route path="/home" component={Home}/>
					<Redirect to="/about"/> // hshshhs会匹配为about,跳转对应的About组件,下面的实现方式也可,任选其一
                      {/* <Route path="/" component={About} /> */} 
          			 {/* <Redirect from="/" to="/about" /> */} 
				</Switch>
			</div>
		</div>
	</div>
</div>

4、路由组件传递参数

首先来看下 路由组件 的默认props,例如在上面的路由组件 About 组件中打印出传过来的props(如果是普通组件)

export default class About extends Component {
	render() {
		console.log(this.props)
		return (
			<h3>我是About的内容</h3>
		)
	}
}

log 图示:

请添加图片描述

说明:(比较常用的字段如下)

  • history
    • action:这个路由规则,如果是追加就是 PUSH ,替换就是REPLACE
    • go:路由跳转(等同于浏览器的前进/回退按钮),大小n为步数,n为正数即前进,负数即后退
    • goForward:等同于浏览器的前进,前进一步
    • goBack:等同于浏览器的回退,/回退一步
    • location:与下面的location字段相同
    • push:追加式增加路由
    • replace:替换式增加路由
  • location
    • pathname:对应 Link 组件中 to 属性 的 pathname
    • state:传参以 state 方式传参的接收key
    • search:传参以 search 方式传参的接收key
  • match
    • isExact:是否是精准匹配得到的
    • params:参数以 params 方式传参的接收key
    • path:Route 组件的path 值
    • url:具体的path,如果携带参数,显示具体的参数值

根据上面的介绍,路由组件传递参数有三种方式:

  • params 参数
  • search 参数
  • state 参数
4.1 params 参数

使用方式:

  • 在 Link 组件中的 to 属性值 直接在路径后面接具体的参数**(/参数一/参数二)**
  • 在 Route 组件中的 path 属性值进行对应,进行声明接收
  • 传递的参数在 this.props.match 中存储,对应的 key 为 params,value 为 {参数一:值一,参数二:值二},直接取值即可

定义与传递参数:

msgObj = {id:'01',title:'消息1'}
{/* 向路由组件传递params参数 */}
<Link className="list-group-item" to={`/about/${msgObj.id}/${msgObj.title}`}>About</Link>

{/* 声明接收params参数 */}
<Route path="/about/:id/:title" component={About}/>

接收参数:

export default class Detail extends Component {
	render() {
		console.log(this.props);
		// 接收params参数
		const {id,title} = this.props.match.params
		return (
			<ul>
				<li>ID:{id}</li>
				<li>TITLE:{title}</li>
			</ul>
		)
	}
}

图示:

请添加图片描述

4.2 search参数

使用方式:

  • 在 Link 组件中的 to 属性值 直接在路径后面以 ? 开头接具体的参数(?xx=xxx&xxx=xxxx)
  • 在 Route 组件中正常进行注册路由
  • 传递的参数在 this.props.location 中存储,对应的 key 为 search,value 为 ?xx=xxx&xxx=xxxx ,需要进行处理

定义与传递参数:

msgObj = {id:'01',title:'消息1'}
{/* 向路由组件传递search参数 */}
<Link className="list-group-item" to={`/about/?id=${msgObj.id}&title=${msgObj.title}`}>About</Link>

{/* search参数无需声明接收,正常注册路由即可 */}
<Route path="/about" component={About}/>

接收参数:

import qs from 'querystring'
export default class Detail extends Component {
	render() {
		console.log(this.props);
		// 接收search参数
		const {search} = this.props.location
		const {id,title} = qs.parse(search.slice(1))
		return (
			<ul>
				<li>ID:{id}</li>
				<li>TITLE:{title}</li>
			</ul>
		)
	}
}

图示:

请添加图片描述

4.3 state参数

使用方式:

  • 在 Link 组件中的 to 属性值 ,指明 state 字段的值
  • 在 Route 组件中正常进行注册路由
  • 传递的参数在 this.props.location 中存储,对应的 key 为 state,value 为 传递的state字段的值

定义与传递参数:

msgObj = {id:'01',title:'消息1'}

{/* 向路由组件传递state参数 */}
<Link className="list-group-item" to={{pathname:'/about',state:{id:msgObj.id,title:msgObj.title}}}>About</Link>

{/* state参数无需声明接收,正常注册路由即可 */}
<Route path="/about" component={About}/>

接收参数:

export default class Detail extends Component {
	render() {
		console.log(this.props);

		// 接收state参数
		const {id,title} = this.props.location.state || {}

		return (
			<ul>
				<li>ID:{id}</li>
				<li>TITLE:{title}</li>
			</ul>
		)
	}
}

图示:

请添加图片描述

5、编程式路由跳转

在第4节,讲解了默认props 的参数,其中几个方法可以实现路由跳转(不仅仅可通过借助浏览器的前进/回退方法)

  • history
    • go:路由跳转(等同于浏览器的前进/回退按钮),大小n为步数,n为正数即前进,负数即后退
    • goForward:等同于浏览器的前进,前进一步
    • goBack:等同于浏览器的回退,/回退一步
    • push:追加式增加路由
    • replace:替换式增加路由

example:

  • 定义了 回退 按钮,使用 this.props.history.goBack() 函数实现回退
  • 定义了 前进 按钮,使用 this.props.history.goForward() 函数实现回退
  • 定义了 go 按钮,使用 this.props.history.go(n) 函数实现跳转,正数即前进,负数即回退
  • 定义了 push查看 按钮,使用 this.props.history.push 函数实现增添路由
  • 定义了 replace查看 按钮,使用 this.props.history.replace 函数实现增添路由
import React, { Component } from 'react'
import {Link,Route} from 'react-router-dom'
import Detail from './Detail'

export default class Message extends Component {
	state = {
		msgObj:{id:'02',title:'消息2'}
	}

	replaceShow = (id,title)=>{
		//replace跳转+携带params参数
		this.props.history.replace(`/home/message/detail/${id}/${title}`)
	}

	pushShow = (id,title)=>{
		//push跳转+携带params参数
		this.props.history.push(`/home/message/detail/${id}/${title}`)
	}

	back = ()=>{
		this.props.history.goBack()
	}

	forward = ()=>{
		this.props.history.goForward()
	}

	go = ()=>{
		this.props.history.go(-2)
	}

	render() {
		const {msgObj} = this.state
		return (
			<div>
				{/* 向路由组件传递params参数 */}
				<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
            	 &nbsp;<button onClick={()=> this.pushShow(msgObj.id,msgObj.title)}>push查看</button>
				&nbsp;<button onClick={()=> this.replaceShow(msgObj.id,msgObj.title)}>replace查看</button>
				<hr/>
				{/* 声明接收params参数 */}
				<Route path="/home/message/detail/:id/:title" component={Detail}/>
                    
				<button onClick={this.back}>回退</button>&nbsp;
				<button onClick={this.forward}>前进</button>&nbsp;
				<button onClick={this.go}>go</button>
			</div>
		)
	}
}

总结

路由在 React 应用实现的过程中至关重要,需要很好的掌握,上面粗略的介绍了一些API与例子,大家在学习的过程中可以试试

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值