• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

React Router5

武飞扬头像
阿泽不会飞
帮助1

1.SPA概念

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

2.什么是路由

一个路由其实就是一个映射关系(k:v)
key为路径,value可能是function 或者是 component

后端路由:

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

前端路由:

浏览器端路由,value是Component,用于展示页面内容
注册路由:< Route path=“/test” component={Test}>
工作过程:当浏览器的path变为/test的时候,当前路由组件就会变成Test组件

前端路由的原理

这个主要是依靠于history,也就是浏览器的历史记录。
浏览器上的记录其实就是一个栈,前进一次就是入栈,后退一次就是出栈。
并且历史记录上有一个监听的方法,可以时时刻刻监听记录的变化。从而判断是否改变路径
History

3.react-router-dom

依赖下载:

npm i react-router-dom@5

react的路由有三类:
web【主要适用于前端】,native【主要适用于本地】,anywhere【任何地方】
在这主要使用web也就是这个标题 react-router-dom

基本的使用:

导航中的a标签改写成Link标签
< Link to=“/路径” >xxx< /Link>
展示区写Route标签进行路径的匹配
< Route path = ‘/路径’ component={组件名称}>
< App>最外侧包裹了一个< BrowserRouter>或者< HashRouter>

<div className="list-group">
  <Link className="list-group-item"  to="/about">About</Link>
  <Link className="list-group-item"  to="/home">Home</Link>
</div>

<div className="panel-body">
  {/* 注册路由,也就是写对应的关系 */}
  <Route path="/about"component={About}/>
    <Route path="/home"component={Home}/>
    </div>

      index.js:
      ReactDOM.render(
      <BrowserRouter>
        <App />
      </BrowserRouter>
      ,document.getElementById("root"))
学新通

那么使用Link代替a标签之后,在页面上会是什么呢,我们发现其实页面上也是把link转化为了a标签

路由组件以及一般组件

1.写法不一样
一般组件:< Demo>
路由组件:< Route path=“/demo” component ={Demo}/>
2.存放的位置一般不同
一般组件:components
路由组件:pages
3.接收的内容【props】
一般组件:写组件标签的时候传递什么,就能收到什么
路由组件:接收到三个固定的属性【history,location,match】

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

因为Link不能够改变标签体,因此只适合用于一些写死的标签。而如果想要有一些点击的效果,使用NavLink.
如下代码,就写了activeClassName,当点击的时候就会触发这个class的样式

{/*NavLink在点击的时候就会去找activeClassName="ss"所指定的class的值,如果不添加默认是active
 这是因为Link相当于是把标签写死了,不能去改变什么。*/}

<NavLink  activeClassName="ss" className="list-group-item"  to="/about">About</NavLink>
<NavLink className="list-group-item"  to="/home">Home</NavLink>

但是可能一个导航又很多标签,如果这样重复的写NavLink也会造成很多的重复性的代码问题。
因此可以自定义一个NavLink:

// 通过{...对象}的形式解析对象,相当于将对象中的属性全部展开
//<NavLink  to = {this.props.to} children = {this.props.children}/>
<NavLink className="list-group-item" {...this.props}/>

在使用的时候:直接写每个标签中不一样的部分就行,比如路径和名称

{/*将NavLink进行封装,成为MyNavLink,通过props进行传参数,标签体内容props是特殊的一个属性,叫做children */}
<MyNavLink to = "/about" >About</MyNavLink>

switch的使用

目的:防止在react寻找对应组件的时候找到后继续向下查找的问题,影响效率
使用方法:

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

换成:

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

4.样式错误,丢失的解决

拿上面的案例来说:

这里面会有一个样式:
学新通
此时,加载该样式的路径为:
学新通
但是在写路由的时候,有的时候就会出现多级目录,

<MyNavLink to = "/cyk/about" >About</MyNavLink>

<Route path="/cyk/about"component={About}/>

这个时候就在刷新页面,就会出现问题:
学新通
样式因为路径问题加载失败,此时页面返回public下面的Index.html
解决这个问题,有三个方法:
1.样式加载使用绝对位置

2.使用 %PUBLIC_URL%

3.使用HashRouter

因为HashRouter会添加#,默认不会处理#后面的路径,所以也是可以解决的

5.模糊匹配和精准匹配

react默认是开启模糊匹配的。
比如:

Home

此时该标签匹配的路由,分为三个部分 home a b;将会根据这个先后顺序匹配路由。
如下就可以匹配到相应的路由:

<Route path="/home"component={Home}/>

但是如果是下面这个就会失败,也就是说他是根据路径一级一级查询的,可以包含前面那一部分,但并不是只包含部分就可以。

当然也可以使用这个精确的匹配 exact={true}
如以下:这样就精确的匹配/home,则上面的/home/a/b就不行了

<Route exact={true}  path="/home" component={Home}/>
  或者
<Route exact path="/home" component={Home}/>

6.初始化路由(兜底的路由配置Redirect的使用)

在配置好路由,最开始打开页面的时候,应该是不会匹配到任意一个组件。这个时候页面就显得极其不合适,此时应该默认的匹配到一个组件。
此时就需要使用Redirect进行默认匹配了。如下的代码就是默认匹配/home路径所到的组件

<Switch>
  <Route path="/about"component={About}/>
  {/* exact={true}:开启严格匹配的模式,路径必须一致 */}
  <Route   path="/home" component={Home}/>
  {/* Redirect:如果上面的都没有匹配到,就匹配到这个路径下面 */}
  <Redirect  to = "/home"/>
</Switch>

7.嵌套路由

简单来说就是在一个路由组件中又使用了一个路由,就形成了嵌套路由。
举个例子来说:
我们在home这个路由组件中又添加两个组件:

APP.jsx:
<Route   path="/home" component={Home}/>
  Home.jsx:
  <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/message"/>
          </Switch>
          </div>
学新通

react中路由的注册是有顺序的,因此在匹配的时候也是按照这个顺序进行的,因此会先匹配父组件中的路由
比如上面的 /home/news的路由处理过程:
1.因为父组件home的路由是先注册的,因此在匹配的时候先去找home的路由,也就是根据/home/news先模糊匹配到/home
2.在去Home组件里面去匹配相应的路由,从而找到了/home/news进行匹配,因此找到了News组件。
但是如果开启精确匹配,就会在第一步的时候卡住,这个时候就走不下去了。因此不要轻易的使用精确匹配

8.向路由传递参数

传递 params 参数

路由:

{msgObj.title}

路由组件

如上,使用了 :id/:title 成功的接收了由 Link 传递过来的 id 和 title 数据
这样我们既成功的实现了路由的跳转,又将需要获取的数据传递给了子组件
我们在子组件组件中打印 this.props 来查看当前接收的数据情况:
学新通

传递 search 参数

父类

{msgObj.title}

采用 search 传递的方式,无需在 Route 中再次声明,可以在 Detail 组件中直接获取到
学新通

子类:

import React, { Component } from 'react'

function GetRequest(url) {
    let code = {};
    let strs = [];
    let str = url.substr(1); //从第一个字符开始 因为第0个是?号 获取所有除问号的所有符串
    strs = str.split("&");   //用等号进行分隔 (因为知道只有一个参数 所以直接用等号进分隔 如果有多个参数 要用&号分隔 再用等号进行分隔)
    for(let i of strs){
        let thisobj=i.split("=");
        code[thisobj[0]]=thisobj[1]
    }
    return code;
}
//函数返回url?后的对象

export default class Comp4 extends Component{

    render(){
        let {search}=this.props.location
        let {id,title}=GetRequest(search)
        return (
            <h3>
                {id}-----{title}
            </h3>
        )
    }
}
学新通

传递 state 参数

父类

学新通

子类

const { id, title } = this.props.location.state || {}//{}防止是空对象

9.路由的跳转

默认情况下,开启的是 push 模式,也就是说,每次点击跳转,都会向栈中压入一个新的地址,在点击返回时,可以返回到上一个打开的地址,
当我们在读消息的时候,有时候我们可能会不喜欢这种繁琐的跳转,我们可以开启 replace 模式,这种模式与 push 模式不同,它会将当前地址替换成点击的地址,也就是替换了新的栈顶
我们只需要在需要开启的链接上加上 replace 即可

编程式路由导航

借助this.prosp.history对象上的API对操作路由跳转、前进、后退
  -this.prosp.history.push()
  -this.prosp.history.replace()
  -this.prosp.history.goBack()
  -this.prosp.history.goForward()
  -this.prosp.history.go(2)//前进两步

我们可以采用绑定事件的方式实现路由的跳转,我们在按钮上绑定一个 onClick 事件,当事件触发时,我们执行一个回调

//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})

//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})
学新通

withRouter

非路由组件无法获得 history 对象
我们需要对哪个组件包装就在哪个组件下引入

// Header/index.jsx
import { withRouter } from 'react-router-dom'
// 在最后导出对象时,用 `withRouter` 函数对 index 进行包装
export default withRouter(index);

这样就能让一般组件获得路由组件所特有的 API

10.BrowserRouter 和 HashRouter 的区别

它们的底层实现原理不一样

对于 BrowserRouter 来说它使用的是 React 为它封装的 history API ,这里的 history 和浏览器中的 history 有所不同噢!通过操作这些 API 来实现路由的保存等操作,但是这些 API 是 H5 中提出的,因此不兼容 IE9 以下版本。
对于 HashRouter 而言,它实现的原理是通过 URL 的哈希值,但是这句话我不是很理解,用一个简单的解释就是
我们可以理解为是锚点跳转,因为锚点跳转会保存历史记录,从而让 HashRouter 有了相关的前进后退操作,HashRouter 不会将 # 符号后面的内容请求。兼容性更好!
地址栏的表现形式不一样

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

刷新后路由 state 参数改变

  1. 在BrowserRouter 中,state 保存在history 对象中,刷新不会丢失
  2. HashRouter 则刷新会丢失 state

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgffgcc
系列文章
更多 icon
同类精品
更多 icon
继续加载