react-day03(Router)
(1)路由介绍---根据url路由不同渲染不同组件
1、安装
npm install --save react-router-dom
安装完毕后,查看package.json项目说明文件,此时该开发依赖已经分配到生产依赖dependencies中
审查后发现该版本为5版本系列,5版本主要针对React Hook做了更好的支持
2、作用
点击不同导航选项时会跳到不同的对应页面,而React主要编写单页面应用(SPA):所有的页面跳转都是由路由操作,主要原理是根据路由不同去切换试图。
SPA页面跳转:
所有的页面跳转都是由路由操作,主要原理是根据路由不同去切换试图
接下来优化下项目初始结构,删除无用文件(serviceWorker.js离线缓存。。。)
并修改入口文件
根组件App.js也做下简化
效果如下所示
但一个应用不可能只有一个页面,所以借着下面操作
之后编写相关组件并导出
除了使用Class类的形式,使用function形式也可以创建组件,如下
接下来在根组件引入
接下来想要的效果是根据路径不同,显示不同的组件页面,类似于百度新闻
首先引入Router的一系列方法
import {BrowserRouter as Router,Switch,Route,Link} from 'react-router-dom'
分析:因为BrowserRouter单词过长,所以这里官方推荐我们用as重命名为Router;Router代表路由器,而Route代表线路;Link用于跳转
接下来结合Route便可以实现路由渲染,如下所示
测试如下
至此便可以实现根据不同的url路由渲染不同组件。
(2)BrowserRouter与HashRouter区别
接下来我们看下两者区别
1、BrowserRouter
表现形式如下
2、HashRouter
表现形式如下
3、区别
HashRouter表现为锚点链接
BrowserRouter没有锚点形式,以斜杠开头,但不能以斜杠结尾。是H5 新特性,主要通过history.push实现。上线之后,需要配合后台进行相关处理(重定向处理404的BUG)
由于此技术仅旨在支持旧版浏览器,因此我们建议配置服务器以供使用<BrowserHistory>
。
(3)Router之Link跳转
本质会被解释为a标签
此时便可以点击导航进行页面展示内容的切换。
接下来将Link换为a链接做下测试
此时仍旧可以实现页面切换跳转。但两者仍存在较大差异,直接用a链接虽然可以跳转,但违背了SPA的初衷,每次跳转都会重新加载相同信息。
正常开发,一般会将该导航组件单独分隔出去,所以借着处理如下
(4)Router之exact匹配规则---精准匹配
需求:访问链接为http://localhost:5000/mine/info时,页面展示info信息组件
此时做下测试
会发现,除了展示Info组件,Mine组件也展示了出来。此时便可以利用exact精准匹配
<Route path="/mine" exact={true} component={Mine}></Route>
默认exact为true,所以,也可以不写赋值。借着做修改,一般访问首页都不带home,所以修改如下
测试如下,会发现每个页面都会将Home组件渲染出来
修改如下,利用exact进行精准匹配,即可解决该问题
(5)Router之strict严格匹配
虽然之前的exact可以进行精准匹配,但某些情况下还不够
场景:有时,我们访问网站时习惯在最后加个/,但开发者并不希望匹配到它。因为有时最后的/可能表示另外一个路径,此时可以通过strict来处理
接下来添加严格匹配属性,处理后的结果如下所示
另外,还有一点要注意,exact精准匹配存在的组件想要添加严格匹配strict时,两者同时存在,不然会无效。
(6)Router之404页面和Switch
当用户访问的url不存在时,做出对应404页面反馈
编写如下
之后进行导入使用
因为是全规则匹配,所以不用添加path,此时测试如下
但此时会发现,每个页面都会渲染404组件
此时便可以利用Switch进行限制,在Switch下只能显示一个组件
(7)Router之render function简约加载方案------加载组件的另一种方式
之前的每个视图都对应一个组件,但有时也可以使用简约方案,来代替简单的组件
除了直接render里写标签内容外,还可以直接调用组件。即将标签内容直接替换为组件调用
而且这种方式也可以传递参数,如下所示
结果如下
这些信息在以后操作会有相关作用。当然,也可以传递其他基本类型数据,如下所示
此外也可以利用解构赋值格式,如下
以上便是极简形式的渲染方法,可以不用component属性,利用render进行直接渲染,也可以手动传递参数
参数传递与路径展示:且该参数没有在路径上进行相关展示,之后会介绍其他参数传递,可以在路径上进行展示
(8)Router之NavLink激活导航高亮
如上所示,在不同页面时,导航会有对应的高亮展示,这时便需要用到<NavLink></NavLink>
接下来对代码做下修改,将所有的Link换为NavLink
接下来坐下测试,此时仍然可以正常切换
此时会发现,被选中的导航,会添加className为active,所以接下来可以给该类名添加样式
然后在Nav.jsx组件引入
测试如下
会发现,在other下除了other对于导航,home首页也被高亮。
原因:
/other包裹在/首页下,所以需要添加exact精准匹配
除了默认的active,也可以自定义激活状态的类名,使用属性activeClassName即可
接着,编写navSelected样式即可
此外也可以使用内联样式style进行状态编写,如下所示
如果activeStyle要直接写到标签里,则需要使用{{}}才可以,如下所示
(9)Router之url parameters---路由传参(单个或多个)---参数传递形式1---parameters参数形式
对于某些页面来说,渲染时传递的参数不同,会导致渲染不同内容。这时便需要通过路由传参进行处理了。这里我们用/mine/info来举例
传递参数时以/开头
<Route path="/mine/info/:id" component={Info}></Route>
此时跳转的组件里,便可以通过props进行接收。在info组件输出测试下
此时便可以通过props.match.params.id来获取传递的id参数
此时便可以根据传参的不同,获取到不同的网络数据
但此时仍然存在,问题,如果不传递参数,会出现404错误,如下所示
此时可以加个参数?,表示传参可有可无,如果不传参数,则默认无即可
<Route path="/mine/info/:id?" component={Info}></Route>
此外,也可以传递多个参数,如下所示
<Route path="/mine/info/:id?/:name?/:age?" component={Info}></Route>
真正开发时,不可能让用户手动传递,一般都是点击跳转时传递,如下所示
<NavLink></NavLink>导航处传递,<Route path="/mine/info/:id?/:name?/:age?" component={Info}></Route>处接受渲染。
(10)Router之url query string---路由传参(单个或多个)---参数传递形式2---query问号形式
除了上述参数传递形式,还有另外一种形式
如果是query问号形式,则可以通过location.search来获取,如下所示
所以接下来有两种读取方案
1、读取方案一:new URLSearchParams(props.location.href).get(name)
接着使用get方法传入对应参数名获取对应值,如下所示
此外还有第二种读取方案,较为简单
2、读取方案二:引入querystring依赖包,然后调用该依赖包的相关方法
测试结果如下
但此时对象前面有个?,如果不去掉则会影响id的读取,所以接着操作如下(转为字符串后,利用正则匹配将其替换)
JSON.stringify(queryParamsObject).replace(/\?/g,"")
(11)Router之to=object(该属性在Link和NavLink的表现一致)+ 隐藏属性state
这里我们拿mine组件导航来举例
接下来在Mine组件做下输出测试
此时点击导航如下所示
分析:此时可以读取到路由设置传参对象里的相关配置,例如通过hash做一些判断等等。。。 此外,还有一个隐藏属性state,不会表现在url里,但是隐性的传递了过来
此外,该隐藏属性可以自定义
state隐性属性优点:可以隐藏传递参数
(12)Router重定向之redirect
1、基础形式,基本用法
此时访问/hello时重定向到/,访问/hellomine时重定向到/mine
表现形式为直接在url进行拦截重定向,此外还有另外一种形式,即跳到新页面后再重定向到其他页面
2、跳转新页面后再进行重定向
场景:选择商品或外卖进行下单时,如果没有登录,则会重定向跳转到登录页面
首先编写商品页面组件,如下所示
测试如下
接下来做个功能,进入该商品页面后重定向到首页。所以首先需要判断登录状态
如果isLogin为true则是已经登录,直接展示该页面的相关信息,否则利用Redirect重定向到首页
这里便可以通过重定向Redirect实现权限功能
(13)Router重定向之push和replace
在mine我的页面点击按钮,重定向到首页
注意:这里我们用的其他方式编写方法,详情见React.Component三种手动绑定this方法,React创建组件的3种写法 ,React.createClass与React.Component区别.
這裡,我們輸出下props
除了上述写法,也可以直接通过this.props操作
所以可以根据push和replace方法操作进行自定义编码重定向,如下所示
两者区别: 1、push为叠加型,上次访问的页面依然存在内存里,可以通过返回键返回上一页 2、replace为替换型,直接替换掉上个页面,无法返回
场景:登录成功后,在接下来利用编码跳转到某个页面
(14)Router之withRouter高阶组件
有时,如果导航操作,没有放置在Router对象下,则组件不会被路由管理,所以没有路由对象。此时如果想在该组件操作路由,需要结合withRouter高阶组件实现
首先编写MineChild组件,作为Mine组件的子组件,然后在Mine组件里调用,如下所示
之后在Mine组件里引用
此时输出空对象,即props为空对象。
原因:
该组件没有放置在Router对象下,则组件不会被路由管理,所以没有路由对象。此时如果想在该组件操作路由,需要结合withRouter高阶组件实现。如下所示
此时this.props输出如下
接下来便可以进行路由操作了,如下所示
(15)Router之prompt---离开确定组件
场景:当前页面有输入框,且里面输入了一些内容,在离开该页面组件时,可能需要提示用户。即类似于钩子函数,在进行路由跳转前进行的一些操作
首先编写组件输入框代码,如下所示
此时输入内容后,离开该页面组件时没有任何提示。所以接下来给其添加提示操作。这里便用到了Prompt
这里使用了正则表达式/^s*$/匹配空行,此时离开页面,进行路由跳转时,会进行输入监听,如下所示
(16)Router之路由嵌套
新建书籍组件BookList,在其下进行路由嵌套
之后在入口文件,进行路由嵌套,如下所示
最终效果如下
.