React路由

目录

SPA的理解

 路由的理解

路由分类

后端路由:

前端路由:

前端路由原理

 react-router-dom

路由的基本使用

路由组件与一般组件

Switch的使用

解决多级路径刷新页面样式丢失的问题

路由的严格匹配与模糊匹配

Redirect的使用    

嵌套路由

路由传参

扫盲ajax请求时携带参数的方式

params参数

search参数

.state参数

push与replace模式

编程式路由导航

withRouter的使用

BrowserRouter与HashRouter的区别

React UI组件库

流行的开源React UI组

antd的按需引入+自定主题


SPA的理解

  1. 单页Web应用(single page web applicationSPA)。
  2. 整个应用只有一个完整的页面
  3. 点击页面中的链接不会刷新页面,只会做页面的局部更新。
  4. 数据都需要通过ajax请求获取, 并在前端异步展现。

 路由的理解

  1. 一个路由就是一个映射关系(key:value)
  2. key为路径, value可能是function或component

路由分类

后端路由:

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

前端路由:

  • 浏览器端路由,valuecomponent,用于展示页面内容。
  • 注册路由: <Route path="/test" component={Test}>
  • 工作过程:当浏览器的path变为/test, 当前路由组件就会变为Test组件

前端路由原理

一般借助 history.js管理https://cdn.bootcss.com/history/4.7.2/history.jsicon-default.png?t=M276https://cdn.bootcss.com/history/4.7.2/history.js

  • 前端路由主要依靠BOM的 api   history(浏览器的历史记录) 不会引发页面刷新
  • let history = History.createBrowserHistory() //方法一,直接使用H5推出的history身上的API 创建 history对象
  • let history = History.createHashHistory() //方法二,hash值(锚点)
  • history.listen 监听路径变化
  • history.push 在浏览历史记录添加一条数据  点击前进后退一条历史记录
  • 浏览器的历史记录是栈结构 (历史记录是进栈出栈) 
  • history.replace(path) 替换上一条历史记录
  • history.goBack()后退  history.goForward()前进
	<script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>
	<script type="text/javascript">
		// let history = History.createBrowserHistory() //方法一,直接使用H5推出的history身上的API
		let history = History.createHashHistory() //方法二,hash值(锚点)

		//在浏览历史记录添加一条数据
		function push(path) {
			history.push(path)
			return false//禁止 A标签跳转
		}
        //替换上一条历史记录
		function replace(path) {
			history.replace(path)
		}

		function back() {
			history.goBack()
		}

		function forword() {
			history.goForward()
		}
        //监听变化
		history.listen((location) => {
			console.log('请求路由路径变化了', location)
		})
	</script>

 react-router-dom

  1. react的一个插件库。
  2. 专门用来实现一个SPA应用。
  3. 基于react的项目基本都会用到此库。

路由的基本使用

  • 1.明确好界面中的导航区、展示区
  •  2.导航区的a标签改为Link标签
  • <Link to="/xxxxx">Demo</Link> 最后会被编译成a标签
  •  3.展示区写Route标签进行路径的匹配 
  • <Route path='/xxxx' component={Demo}/> 路由
  •  4.<App>的最外侧包裹了一个<BrowserRouter>(history 对象)或<HashRouter>(hash值的切换#号后面的值不会发给服务器) 路由器
import React, { Component } from 'react'
import {Link,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">

							{/* 原生html中,靠<a>跳转不同的页面 */}
							{/* <a className="list-group-item" href="./about.html">About</a>
							<a className="list-group-item active" href="./home.html">Home</a> */}

							{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
							<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">
								{/* 注册路由 */}
								<Route path="/about" component={About}/>
								<Route path="/home" component={Home}/>
							</div>
						</div>
					</div>
				</div>
			</div>
		)
	}
}

路由组件与一般组件

 1.写法不同:

  • 一般组件:<Demo/>
  •    路由组件:<Route path="/demo" component={Demo}/>

 2.存放位置不同:

  • 一般组件:components
  •  路由组件:pages

3.接收到的props不同:

  •  一般组件:写组件标签时传递了什么,就能收到什么
  • 路由组件:接收到三个固定的属性  (路由器自带)   
	history:
			go: ƒ go(n)
			goBack: ƒ goBack()
			goForward: ƒ goForward()
			push: ƒ push(path, state)
			replace: ƒ replace(path, state)
	location:
			pathname: "/about"
			search: ""
			state: undefined
	match:
			params: {}
			path: "/about"
			url: "/about"
  • NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
  • 标签体是内容是一个特殊的标签属性
  • 通过this.props.childreen 可以获取标签体内容
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="bgc" className="list-group-item" {...this.props}/>
		)
	}
}
------------------------------------------
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>

Switch的使用

1.通常情况下,path和component是一一对应的关系。

2.Switch可以提高路由匹配效率(单一匹配)。

	<Switch>
    Route path="/about" component={About}/>
	<Route path="/home" component={Home}/>
	<Route path="/home" component={Test}/>//不在匹配
	</Switch>

解决多级路径刷新页面样式丢失的问题

webpack 开启本地服务器后,访问无效路径会返回html主页面

路由路径为多级结构刷新会丢失样式

  • 1.public/index.html 中 引入样式时不写 ./ 写 / (常用)
  •  2.public/index.html 中 引入样式时不写 ./ 写 %PUBLIC_URL% 绝对路径,只适用于react
  • 3.使用HashRouter #号后边为前端资源不在向服务器发请求

路由的严格匹配与模糊匹配

 1.默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)

  2.开启严格匹配:<Route exact={true} path="/about" component={About}/>

  3.严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由

Redirect的使用    

1.一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由

具体编码:

<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>

嵌套路由

1.注册子路由时要写上父路由的path值

2.路由的匹配是按照注册路由的顺序进行的(先匹配一级路由 模糊匹配,在进入二级)

import React, { Component } from 'react'
import MyNavLink from '../../components/MyNavLink'
import {Route,Switch,Redirect} from 'react-router-dom'
import News from './News'
import Message from './Message'

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>
						{/* 注册路由 */}
						<Switch>
							<Route path="/home/news" component={News}/>
							<Route path="/home/message" component={Message}/>
							<Redirect to="/home/news"/>
						</Switch>
					</div>
				</div>
			)
	}
}

路由传参

扫盲ajax请求时携带参数的方式

params:/demo/test/tom/18

query:?name=tom&age=18

body :编码格式 urlencode格式    JSON格式

【urlencoded格式】:

  • 又叫form格式,或者是x-www-form-urlencoded格式。
  • 口诀:表单格式是由键值对组成。键和值之间用=。多个键值对之间用&。例如:name=ZhangSan&age=16

【json 格式】:

  • 口诀1:JSON有对象、数组两种结构,有字符串、数字、逻辑值、空值四种数据类型
  • 口诀2:用大括号{}表示对象。对象是由属性组成的。属性是由键值对组成的。键和值之间用冒号隔开。属性之间用逗号隔开。键必须用双引号引起来。
  • 口诀3:用中括号[] 表示数组。数组由单独的值组成
  • 口诀4:JSON的灵活就灵活在:JSON可以嵌套
     

params参数

  • 路由链接(携带参数):<Link to='/demo/test/tom/18'}>详情</Link>
  •  注册路由(声明接收):<Route path="/demo/test/:name/:age" component={Test}/>
  • 接收参数:this.props.match.params
  • find查找符合项        
<li key={msgObj.id}>
{/* 向路由组件传递params参数 */}
    <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
</li>
{/* 声明接收params参数 */}
<Route path="/home/message/detail/:id/:title" component={Detail} />


------------------------------

const DetailData = [
	{id:'01',content:'你好,中国'},
	{id:'02',content:'你好,世界'},
	{id:'03',content:'你好,未来的自己'}
]
export default class Detail extends Component {
	render() {
		console.log(this.props);
		// 接收params参数
		const {id,title} = this.props.match.params
		const findResult = DetailData.find((detailObj)=>{
			return detailObj.id === id
		})
		return (
			<ul>
				<li>ID:{id}</li>
				<li>TITLE:{title}</li>
				<li>CONTENT:{findResult.content}</li>
			</ul>
		)
	}
}

search参数

  • 路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情</Link>
  • 注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
  • 接收参数:this.props.location.search
  • 备注:获取到的search是urlencoded编码字符串,需要借助querystring解析

qs库 (querystring)

qs.stringify 转为urlencoded编码字符串 name=tom&age=18

qs.parse 转为对象

	{/* 向路由组件传递search参数 */}
<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
{/* search参数无需声明接收,正常注册路由即可 */}
<Route path="/home/message/detail" component={Detail}/>
-----------------------------------

import qs from 'querystring'
const DetailData = [
	{id:'01',content:'你好,中国'},
	{id:'02',content:'你好,世界'},
	{id:'03',content:'你好,未来的自己'}
]
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))

		const findResult = DetailData.find((detailObj)=>{
			return detailObj.id === id
		})
		return (
			<ul>
				<li>ID:{id}</li>
				<li>TITLE:{title}</li>
				<li>CONTENT:{findResult.content}</li>
			</ul>
		)
	}
}

.state参数

路由链接(携带参数):<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>

 注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>

 接收参数:this.props.location.state

 备注:刷新也可以保留住参数,不会暴露在地址栏中,操作的是history对象

为了防止清除浏览器缓存后报错应该写个{}

{/* 向路由组件传递state参数 */}
<Link to={{pathname:'/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}
</Link>
	{/* state参数无需声明接收,正常注册路由即可 */}
<Route path="/home/message/detail" component={Detail}/>

-------------------------------
import React, { Component } from 'react'

const DetailData = [
	{id:'01',content:'你好,中国'},
	{id:'02',content:'你好,世界'},
	{id:'03',content:'你好,未来的自己'}
]
export default class Detail extends Component {
	render() {
		console.log(this.props);

		const findResult = DetailData.find((detailObj)=>{
			return detailObj.id === id
		}) || {}
		return (
			<ul>
				<li>ID:{id}</li>
				<li>TITLE:{title}</li>
				<li>CONTENT:{findResult.content}</li>
			</ul>
		)
	}
}

push与replace模式

push每一次前进后退都会有历史记录 ,展示的是栈顶的一条(默认push)

replace 是替换上一条历史记录  <MyNavLink replace to="/about">About</MyNavLink>

编程式路由导航

history的api

  • this.props.history.goBack()后退
  •  this.props.history.goForward() 前进
  •  this.props.history.go(-2)指定前进或者后退几条历史几录
  • this.props.history.replace 替换历史记录跳转
  • this.props.history.push保存历史记录跳转

export default class Message extends Component {
	state = {
		messageArr:[
			{id:'01',title:'消息1'},
			{id:'02',title:'消息2'},
			{id:'03',title:'消息3'},
		]
	}

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

		//replace跳转+携带search参数
		// this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)

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

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

		//push跳转+携带search参数
		// this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)

		//push跳转+携带state参数
		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 {messageArr} = this.state
		return (
			<div>
				<ul>
					{
						messageArr.map((msgObj)=>{
							return (
								<li key={msgObj.id}>

									{/* 向路由组件传递params参数 */}
									{/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}

									{/* 向路由组件传递search参数 */}
									{/* <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */}

									{/* 向路由组件传递state参数 */}
									<Link to={{pathname:'/home/message/detail',state:{id:msgObj.id,title: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>
								</li>
							)
						})
					}
				</ul>
				<hr/>
				{/* 声明接收params参数 */}
				{/* <Route path="/home/message/detail/:id/:title" component={Detail}/> */}

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

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

				<button onClick={this.back}>回退</button>&nbsp;
				<button onClick={this.forward}>前进</button>&nbsp;
				<button onClick={this.go}>go</button>

			</div>
		)
	}
}
import React, { Component } from 'react'
// import qs from 'querystring'

const DetailData = [
	{id:'01',content:'你好,中国'},
	{id:'02',content:'你好,世界'},
	{id:'03',content:'你好,未来的自己'}
]
export default class Detail extends Component {
	render() {
		console.log(this.props);

		// 接收params参数
		// const {id,title} = this.props.match.params 

		// 接收search参数
		// const {search} = this.props.location
		// const {id,title} = qs.parse(search.slice(1))

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

		const findResult = DetailData.find((detailObj)=>{
			return detailObj.id === id
		}) || {}
		return (
			<ul>
				<li>ID:{id}</li>
				<li>TITLE:{title}</li>
				<li>CONTENT:{findResult.content}</li>
			</ul>
		)
	}
}

withRouter的使用

  • 普通组件不同于路由组件props接收不到 history对象
  • //withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
  • //withRouter的返回值是一个新组件 
  • import {withRouter} from 'react-router-dom'  export default withRouter(Header)

BrowserRouter与HashRouter的区别

1.底层原理不一样:

                        BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。

                        HashRouter使用的是URL的哈希值。

2.path表现形式不一样

                        BrowserRouter的路径中没有#,例如:localhost:3000/demo/test

                        HashRouter的路径包含#,例如:localhost:3000/#/demo/test

 3.刷新后对路由state参数的影响

                        (1).BrowserRouter没有任何影响,因为state保存在history对象中。

                        (2).HashRouter刷新后会导致路由state参数的丢失!!!

4.备注:HashRouter可以用于解决一些路径错误相关的问题。

React UI组件库

流行的开源React UI

 material-ui(国外) 官网: http://www.material-ui.com/#/ 

 ant-design(国内蚂蚁金服)  官网: Ant Design - 一套企业级 UI 设计语言和 React 组件库 

antd的按需引入+自定主题

1.安装依赖:yarn add react-app-rewired customize-cra babel-plugin-import less less-loader

2.修改package.json

"scripts": {
		"start": "react-app-rewired start",
		"build": "react-app-rewired build",
		"test": "react-app-rewired test",
		"eject": "react-scripts eject"
},

 3.根目录下创建config-overrides.js

	//配置具体的修改规则
		const { override, fixBabelImports,addLessLoader} = require('customize-cra');
		module.exports = override(
		fixBabelImports('import', {
		libraryName: 'antd',
		libraryDirectory: 'es',
		style: true,
		}),
		addLessLoader({
		lessOptions:{
		javascriptEnabled: true,
		modifyVars: { '@primary-color': 'green' },
		}
		}),
	);

4.备注:不用在组件里亲自引入样式了,即:import 'antd/dist/antd.css'应该删掉

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值