React基础梳理之【路由】(react中路由有哪些常用组件)
前言
细阅此文章大概需要 15分钟\color{red}{15分钟}15分钟左右
本篇中详细讲述\color{red}{详细讲述}详细讲述了:
单页面应用中的路由模式
多页面应用和单页面应用的对比
Hash和history模式的对比
路由层面上react和vue的差别
React-router-dom的使用
路由模式
路由规则
单一匹配
重定向
路由跳转(标签式)
路由跳转(编程式路由)
路由跳转的几种传参方式
withRouter
如果有任何问题都可以留言给我,我看到了就会回复,如果我解决不了也可以一起探讨、学习。如果认为有任何错误都还请您不吝赐教,帮我指正,在下万分感谢。希望今后能和大家共同学习、进步。
下一篇会尽快更新,已经写好的文章也会在今后随着理解加深或者加入一些图解而断断续续的进行修改。
如果觉得这篇文章对您有帮助,还请点个赞支持一下,谢谢大家!
概要
【在整个
react
中为什么会有dom
?】比如
react-dom
、react-router-dom
,是因为除了react
作为核心 外,还有react-dom
支持h5页面开发 ,以及react-native
支持App的开发而如果vue框架想要实现App的开发,就需要配合uni-app来使用
由于react等前端框架都是基于单页面应用模式来设计的,以实现页面的局部刷新,所以页面的路由模式都是基于(hash或history)两种模式来实现的。
多页面应用和单页面应用的对比
SPA
:单页面WEB应用(single page web application)
(一个产品只有一个页面,所有内容的展示和业务的处理都是在这个页面完成的)
MPA
:多页面WEB应用(multi page web application)
(一个产品包含很多页面,通过页面之前的跳转完成业务逻辑的衔接等)
多页面应用模式(MPA) | 单页面应用模式(SPA) | |
---|---|---|
应用组成 | 由多个完整页面 组成 | 一个外壳页面 和多个页面片段 构成 |
跳转方式 | 页面之间的跳转是从一个页面跳转到另个页面 | 页面片段之间的跳转是把个页面片段删除或隐藏,加载另一个页面片段并显示出来。这是片段之间的模拟跳转,并没有离开壳页面 |
刷新方式 | 整页刷新 | 页面片段局部刷新 |
跳转后公共资源是否重新加载 | 是 | 否 |
url模式 | http://xxx.page1.html http://xxx.page2.html | http://xxx.shell.html#page1 http://xxx.shell.html#page2 |
用户体验 | 页面间切换加载慢,不流畅,用户体验差,特别是在移动设备上 | 页面片段间的切换快,用户体验好,包括在移动设备上 |
能否实现转场动画 | 无法实现 | 容易实现 |
页面间数据传递 | 依赖URL、cookie、或者localStorage,实现麻烦 | 因为在一个页面内,页面片段间传递数据很容易实现 |
搜索引擎优化(SEO) | 可以直接做 | 需要单独方案做,有些麻烦 |
特别适用范围 | 需要对搜索引擎友好的网站 | 对体验要求高的应用,尤其是移动应用 |
开发难度 | 低一些,框架选择容易 | 高一些,需要专门的框架来降低这种模式的开发难度 |
结论 :单页应用模式由于有很多好处,已经是web应用开发的潮流,特别是移动应用开发
hash
和history
模式的对比
hash模式
hash模式是通过
#
在url后拼接参数,再根据规则的不同来渲染不同的组件,此种模式的路由跳转无需服务器的支持【缺点】:url太丑
history模式
没有
#
号,地址栏干净,但后面拼接的地址不是真实地址,需要服务器的支持
react中的路由
路由层面上react和vue
的差别
react中的路由机制与vue,思想上相同,语法上不同
首先react中的路由没有路由表
, 想要在哪个地方渲染不同组件,就要在视图当中的那个地方配置好其路由,一级路由二级路由...都是如此 ,都要在视图当中指定位置进行判断、渲染。并没有单独设置路由表的形式路由规则匹配机制不同
,在react中,并不是某一个路由匹配成功了就不再向下找了,而是接着向下找,如果依然成功就接着找。 而vue中则是,若匹配到一个成功的,就不再向下继续匹配了,所以为了避免渲染多个页面出来,要用<Switch>
标签将所有<Route>
路由规则包裹起来,以实现匹配到一个就不再继续匹配的效果react中路由并没有实现路由懒加载
使用
安装
想要在react中使用路由,则需要先安装react-router-dom
$yarn add react-router-dom
引入
接着想要在组件中使用,就要先引入,并且在引入的过程中,解构出所需的功能
import {} from 'react-router-dom'
HashRouter
hash路由模式BrowserRouter
history路由模式Route
路由规则,根据不同的地址跳转不同的组件Switch
实现路由单一匹配的效果(若成功匹配路由,就不再继续向下匹配了)Redirect
重定向
使用
路由模式(HashRouter/BrowserRouter)
用hash模式举例,若我要使用hash模式,则就在引入之后,在页面入口文件中,用
<HashRouter></HashRouter>
将所有结构包裹起来
路由规则(Router)
若想根据不同的规则渲染不同的组件,就需要使用
<Route>
来配置路由规则Route当中有一些属性,来配置此路由规则
在react路由中,并没有vue一样的路由守卫,所以如果想在路由跳转时判断一些条件:如权限,就可以在
render
函数中进行判断,根据判断来决定是否渲染某组件所以在如
/
等一级路由上,需要使用精准匹配;而/home
则无需使用精准匹配,因为其底下的二级路由也要由此进入;(若只有一级,则看情况使用)若【
path='/'
,则/、/home、/system、/home/xxx
都会被匹配为/
】若【
path='/home'
,则/home、/home/xxx
都会被匹配为/home
】path
匹配地址,但不是精准匹配
exact
精准匹配path(对于匹配度较高的path,如/,最好还是加上exact来进行精准匹配)component
: 对应要渲染的组件render
: 渲染函数(可看作是导航守卫来使用)
单一匹配(Switch)
在react中,并不是某一个路由匹配成功了就不再向下找了,而是接着向下找,如果依然成功就接着找。 所以为了避免渲染多个页面出来,要用
<Switch>
标签将所有<Route>
路由规则包裹起来,以实现匹配到一个就不再继续匹配的效果
重定向(Redirect)
若所有的路由规则都不匹配,那么就重定向到某个组件,比如说首页;使用
<Redirect />
Redirect当中有一些属性,来配置重定向
path
: 要匹配的地址,不使用此属性则为Route没匹配到任何项时to
: 配置重定向跳转的地址exact
: 配置精准匹配
跳转(Navlink)【标签跳转】
编译完成的结果还是a标签
Navlink当中有一些属性,来配置跳转
to
属性可以是一个地址
,也可以是一个对象
,对象当中可以配置三个参数pathname
:地址search
:?xxx=xxx
问号传参的值hash
:hash传值(一般用不到)to
: 用来配置跳转地址,会拿要跳转的地址和路由地址进行匹配,若匹配上,则跳转的同时,会给当前标签加一个active
样式类,让当前标签存在选中样式
【与link的区别,就是是否有active样式】
// 导航组件使用NavLink设置跳转 import { NavLink } from 'react-router-dom' const Nav = function Nav(){ return ( <section className='nav_box'> <h2>OA管理系统</h2> <nav> <NavLink to='/home'>首页</NavLink> <NavLink to={{ pathname='/system', search='?xxx=xxx&xxx=xxx', hash='123123' }} >系统设置</NavLink> </nav> </section> ) } export defaule Nav; 复制代码
跳转(link)【标签跳转】
与NavLink用法一致,只是没有active样式
具体使用见二级路由
编程式跳转【编程式路由】
所有
经过Route路由path规则匹配
之后渲染出来的组件都是受路由管控组件
所有受路由管控的组件,都会默认在props中接收到几个参数
history
: 提供跳转的方法 ,如push
、go
、goBack
....location
: 拿到地址匹配的信息 ,如pathname
、search问号传参参数
、hash
match
: 拿到地址匹配的规则 , 如isExact(是否为精确匹配)
、params(匹配规则的path和当前地址)
路由跳转传参的方式
问号传参
:history.push('/custom/detail?id=${id}');
跳转到目标页面后(/custom/detail),通过
this.props.location.search
获取(注意函数组件和类组件的使用区别)路径传参
(这种方式需要路由配置参与):history.push('/custom/detail/${id}');
<Route path='/custom/detail/:id?' component={CustomDetail} />
跳转到目标页面后(/custom/detail),通过
this.props.match.params
获取(注意函数组件和类组件的使用区别)Link传参(隐式)
: 这种方式地址栏中不显示参数信息{/* link方式 */} <Link to={{ pathname:'/custom/detail', state:{id:id} }} > 客户列表 </Link> {/* 编程式路由跳转方式 */} props.history.push({ pathname:'/home/customadd', state:{ id:100 } }) 复制代码
标签方式
和编程式导航方式
跳转到目标页面后(/custom/detail),通过
this.props.location.state
获取(注意函数组件和类组件的使用区别)弊端:
一旦页面刷新,信息就丢失了
,无法基于state获取场景:
多用于跳转进来填表单,保证一定是从某处跳转而来;保证有些信息不在地址栏显示,安全性提高一些
传递参数
// CustomList组件是基于Route匹配渲染的受路由管控组件 const CustomList = function CustomList(props){ const onClick = ()=>{ /* 路径传参,需要配合Route配置 */ // props.history.push(`/home/customadd/${100}`); /* 问号传参 */ // props.history.push({ // pathname:'/home/customadd', // search:'?id=100' // }) /* 隐式传参 */ props.history.push({ pathname:'/home/customadd', state:{ id:100 } }) } return ( <div> 客户列表 <button onClick> 编辑</button> </div> ) } export defaule CustomList; 复制代码
接收参数
// CustomAdd中接收路由传递的参数 const CustomAdd = function CustomAdd(props){ // 接收路径传参 console.log('获取路径传参传递的值') console.log(props.match.params) // 接收问号传参 console.log('获取问号传参传递的值') console.log(props.location.search) // 接收隐式传参 console.log('获取问号传参传递的值') console.log('当页面刷新,参数丢失') console.log(props.location.state) return ( <div> 新增客户 </div> ) } export defaule CustomAdd; 复制代码
把不受路由管控组件变为受路由管控组件(withRouter)
目的:
在其props中可以使用history、location、match
// withRouter import { NavLink,withRouter } from 'react-router-dom' const Nav = function Nav(props){ console.log(props.history) console.log(props.location) console.log(props.match) return ( <section className='nav_box'> <h2>OA管理系统</h2> <nav> <NavLink to='/home'>首页</NavLink> <NavLink to={{ pathname='/system', search='?xxx=xxx&xxx=xxx', hash='123123' }} >系统设置</NavLink> </nav> </section> ) } export defaule withRouter(Nav); 复制代码
一级路由
// 一级路由 // 使用hash路由,配置route路由规则(exact精准匹配),使用Switch来单一匹配,使用Redirect来重定向 import { HashRouter, Route, Redirect, Switch } from 'react-router-dom'; const App = function App(){ return( <HashRouter> <Nav /> <section className='content'> {/*<System />*/} {/*<Home />*/} <Switch> {/* 一般不会出现【两个地址渲染同一个组件】的情况,所以如果确实两个地址要匹配同一个组件,就要使用重定向的形式 */} {/* <Route path='/' component={Home}/> */} <Redirect path='/' exact to='/home'/> <Route path='/home' component={Home}/> {/* 路由中的权限校验,render函数 */} <Route path='/person' component={Person} render={()=>{ if(isPm){ return <Person /> } return <Redirect to='/login'/> }}/> <Route path='/system' component={System}/> {/* 最后全部没有匹配到的重定向要写在最后 */} <Redirect to='/home'/> </Switch> </section> </HashRouter> ) } export default App; 复制代码
二级路由
在一级路由中配置过路由模式了,二级路由中就不用再配了
依然需要Switch
// 二级路由 import { Route, Redirect, Switch, Link } from 'react-router-dom'; const Home = function Home(){ return( <> <section className='menu_Box'> {/* Link跳转 */} <Link to={{ pathname:'/home/customlist', search:'?lx=all' }} >客户列表</Link> <Link to='/home/customadd'>新增客户</Link> </section> <section className='form_Box'> <Switch> {/* 一般不会出现【两个地址渲染同一个组件】的情况,所以如果确实两个地址要匹配同一个组件,就要使用重定向的形式 */} <Redirect path='/home' exact to='/home/customlist'/> <Route path='/home/customlist' component={CustomList}/> <Route path='/home/customadd' exect component={CustomAdd}/> {/* 若要在customlist组件跳转customadd组件时使用路径传参,就需要在这里route进行配置,而同样不需要配置的route也保留,但要加exect,避免提前匹配导致拿不到参数 */} <Route path='/home/customadd/:id?' component={CustomAdd}/> {/* 最后全部没有匹配到的重定向要写在最后 */} <Redirect to='/home/customlist'/> </Switch> </section> </> ) } export default Home;
作者:Hypnotize
链接:https://juejin.cn/post/7038263724045500446
伪原创工具 SEO网站优化 https://www.237it.com/