• React路由(含新老版对比)


    React路由

    源码地址:https://github.com/BLKNjyty/reactstudy

    npm install --save react-router-dom
    
    • 1

    SPA

    1. 单页Web应用(single page web application,SPA)。

    2. 整个应用只有一个完整的页面

    3. 点击页面中的链接不会刷新页面,只会做页面的局部更新。

    数据都需要通过ajax请求获取, 并在前端异步展现。

    路由

    理解:

    1.一个路由就是一个映射关系(key:value)

    1. key为路径, value可能是function或component

    分类

    1. 后端路由:

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

      2. 注册路由: router.get(path, function(req, res))

      3. 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据

    2. 前端路由:

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

      2. 注册路由:

      3. 工作过程:当浏览器的path变为/test时, 被前端路由器检测到了路径变化,当前路由组件就会变为Test组件

    前端路由的原理

    依赖于浏览器浏览历史工作,

    见:其他 -前端路由的基石 ,由此可见,有两种方法控制浏览器

    DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>前端路由的基石_historytitle>
    head>
    <body>
    	
    	<a href="http://www.atguigu.com" onclick="return push('/test1') ">push test1a><br><br>
    	<button onClick="push('/test2')">push test2button><br><br>
    	<button onClick="replace('/test3')">replace test3button><br><br>
    	<button onClick="back()"><= 回退button>
    	<button onClick="forword()">前进 =>button>
    
    	<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
    		}
    		//replace是替换栈顶的那条历史记录
    		function replace (path) {
    			history.replace(path)
    		}
    
    		function back() {
    			history.goBack()
    		}
    
    		function forword() {
    			history.goForward()
    		}
    		//监听url路径的变化
    		history.listen((location) => {
    			console.log('请求路由路径变化了', location)
    		})
    	script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    react-router-dom

    1. react的一个插件库。

    2. 专门用来实现一个SPA应用。

    3. 基于react的项目基本都会用到此库。

    基本用法

    路由组件和基本组件

    ​ 1.写法

    //一般
    <Demo/>
    //路由组件
    <Routes>
    		<Route path="/about" element={<About/>}/>
    		<Route path="/home" element={<Home/>}/>
    </Routes>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ​ 2.放的位置应该不一样

    ​ 3.接受的props不同,一般组件一般是传递了什么就接收什么。

    ​ 路由组件接受三个固定属性:history,location,match

    history:
    	go:
    	goBack:
    	goForward:
    	push:
    	replace:
    location:
    	pathname:获取当前的路由路径
    	search:
    	state:
    match:
    	params:
    	path:获取当前的路由路径
    	url:获取当前的路由路径
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    简单案例

    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中,靠跳转不同的页面 */}
    							{/* About
    							Home */}
    							
    							{/* 在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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    Home About

    export default class Home extends Component {
    	render() {
    		return (
    			<h3>我是Home的内容</h3>
    		)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    export default class About extends Component {
    	render() {
    		console.log('About组件收到的props是',this.props);
    		return (
    			<h3>我是About的内容</h3>
    		)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    NavLink

    在React中靠路由链接实现切换组件–编写路由链接

    ​ About

    ​ Home

    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">
    
    							{/* 原生html中,靠跳转不同的页面 */}
    							{/* About
    							Home */}
    
    							{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
    							<NavLink activeClassName="atguigu" className="list-group-item" to="/about">About</NavLink>
    							<NavLink activeClassName="atguigu" className="list-group-item" to="/home">Home</NavLink>
    						</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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    export default class Header extends Component {
    	render() {
    		// console.log('Header组件收到的props是',this.props);
    		return (
    			<div className="page-header"><h2>React Router Demo</h2></div>
    		)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    封装自己的NavLink

    export default class MyNavLink extends Component {
    	render() {
    		// console.log(this.props);
    		return (
    			<NavLink activeClassName="atguigu" className="list-group-item" {...this.props}/>
    		)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    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">
    
    							{/* 原生html中,靠跳转不同的页面 */}
    							{/* About
    							Home */}
    
    							{/* 在React中靠路由链接实现切换组件--编写路由链接 
    								标签体的值是key为children的标签属性的值传递过去了,MyNavLink组件的{...this.props}直接接受了这个参数:
    									children:About
    							*/}
    							<MyNavLink to="/about">About</MyNavLink>
    							<MyNavLink to="/home">Home</MyNavLink>
    						</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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    Switch

    {/* 注册路由,/home下有两个路由组件,加入switch之后,匹配到第一个就不会再匹配了 */}
    								<Switch>
    									<Route path="/about" component={About}/>
    									<Route path="/home" component={Home}/>
    									<Route path="/home" component={Test}/>
    								</Swtch>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    样式丢失

    原因:

    ​ 路由多级时这时刷新,样式会丢失!

    ​ 原因:

    ​ index.html的样式引入改为,点表示当前目录

    ​ 解决办法:

    ​ 1.将index.html的样式引入改为

    ​ 2.将index.html的样式引入改为

    ​ 3.使用HashRouter代替BrowserRouter,因为将url的#后的值视为无效

    ​ 当请求的东西不存在,则把public下的index.html返回 (这是脚手架设置的)

    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">
    
    							{/* 原生html中,靠跳转不同的页面 */}
    							{/* About
    							Home */}
    
    							{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
    							<MyNavLink to="/atguigu/about">About</MyNavLink>
    							<MyNavLink to="/atguigu/home">Home</MyNavLink>
    						</div>
    					</div>
    					<div className="col-xs-6">
    						<div className="panel">
    							<div className="panel-body">
    								{/* 注册路由
    								路由多级时这时刷新,样式会丢失!
    								原因:
    								index.html的样式引入改为,点表示当前目录
    								解决办法:
    								1.将index.html的样式引入改为
    								2.将index.html的样式引入改为
    								3.使用HashRouter代替BrowserRouter,因为将url的#后的值视为无效
    								当请求的东西不存在,则把public下的index.html返回 (这是脚手架设置的)*/}
    								<Switch>
    									<Route path="/atguigu/about" component={About}/>
    									<Route path="/atguigu/home" component={Home}/>
    								</Switch>
    							</div>
    						</div>
    					</div>
    				</div>
    			</div>
    		)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    exact

    {/* 注册路由 exact开启了严格匹配 */}
    <Switch>
    	<Route exact path="/about" component={About}/>
    	<Route exact path="/home" component={Home}/>
    </Switch>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Rediect

    {/* 注册路由 Redirect 谁都匹配不上  跳转的路由*/}
    <Switch>
    	<Route path="/about" component={About}/>
    	<Route path="/home" component={Home}/>
    	<Redirect to="/about"/>
    </Switch>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    二级路由

    home路由下面增加Message和News路由

    export default class Home extends Component {
    	render() {
    		return (
    				<div>
    					<h3>我是Home的内容</h3>
    					<div>
    						<ul className="nav nav-tabs">
    							{/* 在父路由的下面接着写路由
    							/home/news 模糊匹配,和Home路由也匹配,所以父组件也会展示
    							/home/news 模糊匹配,又和news路由匹配
    							所以不能开启严格匹配
    							*/}
    							<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>
    			)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    路由组件传递参数

    点击Message页面的详细信息链接在下面显示detail,并且把参数传递过去

    params参数

    export default class Message extends Component {
    	state = {
    		messageArr:[
    			{id:'01',title:'消息1'},
    			{id:'02',title:'消息2'},
    			{id:'03',title:'消息3'},
    		]
    	}
    	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>
    								</li>
    							)
    						})
    					}
    				</ul>
    				<hr/>
    				{/* 声明接收params参数 */}
    				<Route path="/home/message/detail/:id/:title" component={Detail}/>
    			</div>
    		)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    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>
    		)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    search参数(query参数)

    export default class Message extends Component {
    	state = {
    		messageArr:[
    			{id:'01',title:'消息1'},
    			{id:'02',title:'消息2'},
    			{id:'03',title:'消息3'},
    		]
    	}
    	render() {
    		const {messageArr} = this.state
    		return (
    			<div>
    				<ul>
    					{
    						messageArr.map((msgObj)=>{
    							return (
    								<li key={msgObj.id}>
    
    
    									{/* 向路由组件传递search参数 */}
    									<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
    
    								</li>
    							)
    						})
    					}
    				</ul>
    				<hr/>
    				{/* 声明接收params参数 */}
    				{/*  */}
    
    				{/* search参数无需声明接收,正常注册路由即可 */}
    				<Route path="/home/message/detail" component={Detail}/>
    
    			</div>
    		)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    // qs有两个有用的功能:
    //针对urlencoding编码:key=value&key1=value1==>qs
    //将json对象格式转化为此编码格式:qs.stringfy(urlencoding);反过来qs.paese(json)
    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>
    		)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    state参数

    export default class Message extends Component {
    	state = {
    		messageArr:[
    			{id:'01',title:'消息1'},
    			{id:'02',title:'消息2'},
    			{id:'03',title:'消息3'},
    		]
    	}
    	render() {
    		const {messageArr} = this.state
    		return (
    			<div>
    				<ul>
    					{
    						messageArr.map((msgObj)=>{
    							return (
    								<li key={msgObj.id}>
    
    									{/* 向路由组件传递state参数 */}
    									<Link to={{pathname:'/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link>
    
    								</li>
    							)
    						})
    					}
    				</ul>
    				<hr/>
    
    				{/* state参数无需声明接收,正常注册路由即可 */}
    				<Route path="/home/message/detail" component={Detail}/>
    
    			</div>
    		)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    const DetailData = [
    	{id:'01',content:'你好,中国'},
    	{id:'02',content:'你好,尚硅谷'},
    	{id:'03',content:'你好,未来的自己'}
    ]
    export default class Detail extends Component {
    	render() {
    		console.log(this.props);
    		// 接收state参数,刷新页面  上述三种参数传递方式 参数都不会丢失
    		//为防止查出来是undefined(比如清除了缓存或者就没传递数据),则使用{}空对象,防止浏览器报错
    		//HashRouter路由会导致参数的丢失
    		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>
    		)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    编程时路由导航

    即不靠路由标签Link或者MyNavLink 标签

    自己写函数完成路由的跳转

    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}>
    									{/* 向路由组件传递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参数 */}
    				{/*  */}
    
    				{/* search参数无需声明接收,正常注册路由即可 */}
    				{/*  */}
    
    				{/* 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>
    		)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    withRouter

    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>
    		)
    	}
    }
    
    export default withRouter(Header)
    
    //withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
    //withRouter的返回值是一个新组件
    //要不然一般组件就没有路由组件的history这些api
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    BrowerRouter和HashRouter路由器的区别

    1.底层原理不一样:

    ​ BrowerRouter使用的时h5的history(不是this.props.history这个,这个是React对h5的history的封装),不兼容ie9以及以下版本

    ​ HashRouter使用的时URL的哈希值

    2.url表现形式不一样:

    ​ BrowerRouter没有#,如:localhost:3000/demo/test

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

    3.刷新后对路由state参数的影响(重要)

    ​ BrowerRouter没有影响,因为statev保存在state对象中

    ​ HashRouter刷新为导致state参数丢失

    4.HashRouter可以用来解决一些路径错误的相关问题(比如样式丢失的问题)

    React6路由

    区别

    element代理component

    Routes

    1.代替Switch

    2.和Route配合使用,Route外边必须包裹Routes

    3.Route相当于if语句,如路径和当前的url匹配,则呈现对应的组件

    4.属性用于指定:路径匹配知否忽略大小写(more那位false)

    5.当路由变化是,Routes匹配所有的Route元素找到最佳的匹配并呈现组件

    6.Routes也可以嵌套使用,且配合useRoutes配置路由表,但需要通过Outlet组件来渲染子路由

    重要:使用useRoutes

    路由表

    export default [
        {
          path:'/about',
          element:<About/>
        },
        {
          path:'/home',
          element:<Home/>,
          children:[
            {
                path:'news',
                element:<News/>
            },
            {
              path:'message',
              element:<Message/>,
              children:[
                {
                  // path:'detail/:id/:title',
                  path:'detail',
                  element:<Detail/>
                }
              ]
          }
          ]
        },
        {
          path:'/',
          element:<Navigate to="/about"/>
        }
      ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    路由表暴露在App.jsx中,

    import { useRoutes} from 'react-router-dom'
     // 路由表,根据路由表生成路由
      const element=useRoutes(routes)
      
      //在函数组件的return片段需要注册路由的片段中添加
      {element}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    例子:

    end:子路由匹配到,父路由就不高亮了。

    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">
    
                  <NavLink className={computedClassName} to="/about">About</NavLink>
    							<NavLink className={computedClassName} end to="/home">Home</NavLink>
    						</div>
    					</div>
    					<div className="col-xs-6">
    						<div className="panel">
    							<div className="panel-body">
                    {element}
    							</div>
    						</div>
    					</div>
    				</div>
    			</div>
    		)
            
    function  computedClassName({isActive}){
      //console.log(isActive)
      return isActive ? 'list-group-item atguigu' : 'list-group-item' 
    }        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    Navigate代替Redirect

    只要被渲染在页面上就会切换视图

    除了to属性,还有replace属性。

    //1.在路由表中,表示url以/结尾默认展示about组件
    {
          path:'/',
          element:<Navigate to="/about"/>
        }
    //2.满足条件即跳转,比如当前页面的sum变为2时,自动跳转为about组件(替换当前的home组件)
    export default function Home() {
    	const [sum, setSum] = React.useState(1)
    
    
    	return (
    		<div>
    			<h3>我是Home的内容</h3>
    			{/* 

    {this.state.sum}

    */
    } {sum === 2 ? <Navigate to="/about" replace={false} /> : <h4>当前的sum值是{sum}</h4>} <button onClick={() => setSum(sum => sum + 1)}>点击将sum变为2</button> </div> ) }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    NavLink高亮

     computedClassName({isActive}){
        console.log(isActive)
        return isActive ? 'list-group-item atguigu' : 'list-group-item' 
     }
    //不可以在标签里直接用activeClassName="atguigu" 这种形式了
    Home
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    参数携带

    点击message组件中的链接,在下方展示另外一个组件,里面有传递过去的内容

    export default function Message() {
    	const [messageArr,setessageArr] = React.useState(
    		 [
    			{ id: '01', title: '消息1' },
    			{ id: '02', title: '消息2' },
    			{ id: '03', title: '消息3' },
    		 ]
    		)
    	return (
    		<div>
    			<ul>
    				{
    					messageArr.map((msgObj) => {
    						return (
    							<li key={msgObj.id}>
    								{/* 向路由组件传递params参数 */}
    								{/* {msgObj.title} */}
    								{/* search参数 */}
    								{/* {msgObj.title} */}
    								<Link to="detail" state={{
    									id: msgObj.id,
    									title: msgObj.title,
    								}}>{msgObj.title}</Link>
    							</li>
    						)
    					})
    				}
    			</ul>
    			<hr />
    			<Outlet />
    		</div>
    	)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    {
          path:'/home',
          element:<Home/>,
          children:[
            {
                path:'news',
                element:<News/>
            },
            {
              path:'message',
              element:<Message/>,
              children:[
                {
                //params传参数需要声明,其他两种不需要
                  // path:'detail/:id/:title',
                  path:'detail',
                  element:<Detail/>
                }
              ]
          }
          ]
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    const DetailData = [
    	{ id: '01', content: '你好,中国' },
    	{ id: '02', content: '你好,尚硅谷' },
    	{ id: '03', content: '你好,未来的自己' }
    ]
    export default function Detail() {
    
    	// console.log(this.props);
    	//`接收params参数
    	// const { id, title } = useParams()
    	
    	//接收search参数,用于更新接收到的参数setSearch(`id=0001&title=hahha`)
    	// const  [search,setSearch]=useSearchParams()
    	// const id=search.get('id')
    	// const title=search.get('title')
    
    	//state对象
    	const {state:{id,title}}=useLocation()
    	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>
    	)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    函数式路由导航

    不需要Link navLink,比如点击图片跳转的时候或者点击一个自定义标签跳转的时候

    使用useNavigate进行自定义跳转,同时这种形式只能接收state参数,可以设置跳转类型push/replace

    export default function Message() {
    	const [messageArr,setessageArr] = React.useState(
    		 [
    			{ id: '01', title: '消息1' },
    			{ id: '02', title: '消息2' },
    			{ id: '03', title: '消息3' },
    		 ]
    		)
    	const navigate=useNavigate()
    	function showDetail(msgObj){
    		navigate('detail',{
    			replace:false,
    			// paramhe search参数不能这样写,直接写在路径上
    			state:{
    				id:msgObj.id,
    				title:msgObj.title
    			}
    		})
    	}
    
    	return (
    		<div>
    			<ul>
    				{
    					messageArr.map((msgObj) => {
    						return (
    							<li key={msgObj.id}>
    								<Link to="detail" state={{
    									id: msgObj.id,
    									title: msgObj.title,
    								}}>{msgObj.title}</Link>
    								<button onClick={()=>showDetail(msgObj)}>展示详情</button>
    							</li>
    						)
    					})
    				}
    			</ul>
    			<hr />
    			<Outlet />
    		</div>
    	)
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    路由跳转操作

    export default function Header() {
        const navigate=useNavigate()
    
        function back(){
            navigate(-1)
        }
    
        function forward(){
            navigate(1)
        }
        return (
            <div className="col-xs-offset-2 col-xs-8">
                <div className="page-header"><h2>React Router Demo</h2></div>
                <button onClick={forward}>前进</button>
                <button onClick={back}>后退</button>
            </div>
        )
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    useInRouterContext

    如果组件在Router的上下文呈现,则其返回true,否则返回false

    //一般,表示APP 及其子组件都是在上下文环境中,即被被BrowserRouter包裹(不区分路由和非路由组件)
    ReactDOM.render(
    	<BrowserRouter>
    		<App/>
    	</BrowserRouter>,
    	document.getElementById('root')
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    useNavigationType

    返回用户是如何来到当前页面的

    返回值:

    ​ pop,push,replace

    备注:

    ​ pop是指在浏览器中直接打开路由组件(刷新当前页面)

    useOutlet

    作用:用来呈现当前组件中渲染的嵌套路由组件

    const result=useOutLet()
    console.log(result)
    //如果嵌套路由组件已经挂在,则显示嵌套路由对象,否则为null
    
    • 1
    • 2
    • 3

    useResolvedPath

    解析一个url,解析其中的path,search,hash

    本文参考b站尚硅谷视频 链接

  • 相关阅读:
    力扣每日一题46:全排列
    uniapp:swiper-demo效果
    手写call、apply、bind方法及区别总结
    modelsim实现二选一以及D触发器并仿真
    Axure绘制省市县地址输入器
    Arduino驱动LIS2DH三轴加速度传感器(惯性测量传感器篇)
    处理Blob打印Excel
    SpringMVC执行流程-JSP模式
    SQL-Labs靶场“32-33”关通关教程
    5.mongodb 备份与恢复
  • 原文地址:https://blog.csdn.net/weixin_43604021/article/details/126242195