react路由详解

691 阅读9分钟

知识点01-React路由配置

路由:在前端框架里面,单页面应用开发一般都要配合路由类完成。

后端路由

作用:将请求的URL地址和对应Nodejs函数关联在一起

http://web.woninlab.com:8005/add/useradd
http://web.woniulab.com:8005/registers 404 get post

将你的路径发送给指定的服务器,web.woninlab.com来进行定位。8005定位你服务器里面某个应用程序

/add/useradd:定位到你应用程序里面的某个代码片段

router.get("/add/useradd",function(req,res,next){
    Controller处理业务
})
router.post("/add/stuadd",function(){
    
})

总结:后端路由的作用,就是将你的浏览器URL地址和Nodejs里面函数绑定在一起,执行对应的业务逻辑

前端路由

前端路由和路由都是一样的作用,但是前端路由作用对象不一样

http://127.0.0.1:3000/user

将浏览器地址和页面的UI组件绑定在一起。

使用路由的时候,会有几种模式。hash模式 history模式

不管是React框架还是Vue框架,路由实现都是基于Window对象里面history、location来完成的。只是他们提供的路由已经对底层代码做了封装,你直接配置文件就可以了。

window对象提供了history

你们使用history路由模式,需要用到history里面的两个api pushState replaceState(push、replace)

push(pushState):跳转过后会记录跳转历史记录。返回

replace(replaceState):不会记录历史记录,无法返回到上一级。默认返回

H5路由跳转

React路由搭建

React 官方并没有明确指定我们要使用哪个组件来完成路由设计,平时在开发过程中需要使用费路由可以用第三方的路由来搭配使用。推荐一个React-Router的组件来完成路由设计

React-Router能够完成路由的基础功能,hash功能,history、路由跳转、参数传递

访问React-Router组件:reactrouter.com/web/api/Red…

  1. 将路由组件下载到本地

    yarn add react-router-dom
    npm install react-router-dom
    
  2. 项目中引入路由组件

    下载react-router-dom其实也是一个组件,import导入路由组件提供组件来完成路由配置

    import {Route,Switch,Redirect,HashRouter} from "react-router-dom"
    

    通过react-router-dom引入你项目中需要的路由组件来搭建路由就可以

    <HashRouter>
        {/* Switch组件相当于程序switch 默认匹配一个 */}
        <Switch>
            {/* 映射关系,将路径和UI组件映射在一起 */}
            <Route path="/login" component={Login}></Route>
            <Route path="/register" component={Register}></Route>
        </Switch>
    </HashRouter>
    

    在React中你要指定在哪个地方渲染路由,将这个配置放在指定的位置。默认作为渲染出口

  3. 路由配置的其他内容

    路由器:也是两个不同的组件 HashRouter(hash路由器,使用这个路由器,地址栏出现hash#代码)BrowerRouter:使用常规的地址模式,地址栏里面没有#,一般在网站开发过程中你使用hash,最后项目上线的时候,推荐用正常模式。路径美观一些

    路由匹配器:Switch和Router组件,Switch这个组件跟 编程switch代码是一个意思,代表默认只能匹配到一个结果,匹配成功后面就不会在执行。效率和性能,如果你的Swich在匹配过程中没有任何一个Router能够映射成功,默认返回null(不渲染任何内容)

    特点就是匹配到一个就停止匹配。路径有可能会出现包含关系。后面匹配就失败

    <Route exact path="/" component={Login}></Route>
    

    exact:代表精确匹配的意思,值不对那就无法映射

    当你你不用exact匹配路由的时候,你可以将模糊的地址放在Switch最后,从精确到模糊匹配方式

    <Route path="/login" component={Login}></Route>
    <Route path="/register" component={Register}></Route>
    <Route path="/" component={Login}></Route>
    

    对于Route这个组件,我们作用就是映射关系

    <Route path="/login" component={Login}></Route>
    替换为:
    {/* 插槽 */}
    <Route path="/register">
        <Register></Register>
    </Route>
    

    推荐你们 用第一种方式,第二种方式在使用过程中,一级路由完成没有差别,但是如果你有二级路由嵌套。二级路由访问会出问题。

    导航:路由配置成功后,我们通过导航来进行跳转

    Link:这个组件可以跳转到指定的组件 router-link activeClass

    NavLink:点击过后触发默认的一些配置,比如导航颜色

    你可以直接在组件中使用他们来完成页面跳转。最终浏览器会将组件解析为a标签的方式来进行渲染

    重定向:如果你获取到某个路径,这个路径暂时不需要组件来匹配,你可以重定向到其他组件

    <Redirect exact from="/" to="/login" ></Redirect>
    

    from:匹配到的路径

    to:重定向到哪个位置

    知识点03-嵌套路由

在开发中我们将二级路由三级路由等等都统称为嵌套路由。在React中要配置嵌套路由,跟一级配置没有太大的区别,有些约定熟成的阿规范

二级路由的匹配规则

<div className="content">
    {/* <BrowserRouter> */}
    <Switch>
        <Redirect exact from="/home" to="/home/flowrs"></Redirect>
        <Route path="/home/flowrs" component={Main}></Route>
        <Route path="/home/data" component={Data}></Route>
        <Route path="/home/emp" component={Emp}></Route>
    </Switch>
    {/* </BrowserRouter> */}
</div>

在指定的组件里面在加载Switch,和Route组件,指定就在这个位置完成二级路由的渲染

需要注意:二级路由不需要在使用路由器。项目中只需要配置一级路由的路由器就可以完成页面跳转,路由匹配

知识点04-路由跳转

比如:从登录跳转到注册,从注册跳转登录。从登录跳转主页

一、通过导航组件来完成

Link = ""
NavLink to=""

二、脚本的跳转

在React的组件中,你需要跳转可以通过props里面传递的history对象来进行跳转

push:跳转过程中会记录历史记录,可以返回上次的记录

replace:替换了一个路径,无法在返回到上一页页面

navigateTo = ()=>{
       console.log(this.props);
    //    this.props.history.push("/register")
       this.props.history.replace("/register")
    }

在框架里面提供的Link、NavLink router-link最终在webpack打包的时候默认都会解析为a标签/但是一般不推荐大家直接用。是因为在跳转的过程中,组件的方式需要做一些解析。包括后续参数传递。动态添加样式

在路由里面跳转的时候,props默认多了三个对象

history:代表历史记录,里面包含跳转的api,以及对路径一些api操作

location:跳转的路径信息,参数的匹配

match:也是对路径信息记录,参数一些匹配

组件的分类:

  1. 路由组件:页面,登录、注册、主页、main这些都是通过路由来进行加载

  2. 非路由组件:import的方式引入到指定的组件中

    非路由组件身上默认不会给props添加路由的三个对象。无法跳转

非路由组件无法获取到history,你可以使用下面的方案来解决

  1. 路由组件将props的对象传递给子组件,可以继续往下传递,只要有history那就可以跳转

    <Header {...this.props}></Header>
    logout =()=>{
            // console.log("Header",this.props);
            this.props.history.push("/login")
        }
    

    缺点:如果组件嵌套比较多,每一层逐层传递,有些组件不需要也必须作为一个载体来获取history

  2. 可以通过高阶组件来完成效果

    高阶段组件:本质上也是一种组件,但是高阶组件可以接受一个组件作为参数。返回一个新的组件。

    高阶函数:定义一个函数,这个函数接受一个函数作为参数,最后在返回一个函数。

    高阶组件就是一种特殊的高阶函数,高阶组件的代码,最终以高阶函数的形式存在

    闭包:闭包不需要接受一个函数。

    function add(fn1){
        //对原来的函数进行增强处理
        return function(){
            //处理完成过后的函数结果
        }
    }
    

    IIFE就是典型高阶函数

    function map(fn1){
       array
       let newarray = []
       for(let i=0,i<array.length;i++){
           fn1(array[i])
           newarray.push*()
       }
        return newarray
    }
    const arr = array.map(function(item){
        console.log(item)
    })
    

    高阶组件如何完成:需要引入withRouter这个组件来对原来组件进行包装

    import React, { Component } from 'react'
    import {Link,withRouter} from "react-router-dom"
    // import Content from "xxx"class Header extends Component {
        logout =()=>{
            console.log("Header",this.props);
            // this.props.history.push("/login")
        }
        render() {
            return (
                <div style={{width:"100%",height:"80px",backgroundColor:"black"}}>
                    <button onClick={this.logout}>注销</button>
                    <Link to="/login">注销</Link>
                </div>
    ​
           
            )
        }
    }
    export default withRouter(Header)
    ​
    

    在暴露对组件,需要将Header组件放在withRouter里面进行组件的包装,当前这个组件身上props就默认会添加三个路由对象

    模拟高阶组件实现:

    const withRouter = (comp)=>{
        return ()=>{
            return <Route component={comp}>
        }
    }
    

知识点05-路由参数传递

在页面直接使用路由跳转的时候,可以给其他组件传递参数,用于数据更新

应用场景:查看详情、修改数据

window.location.href="/home?id=1&name=xiaowang"
const url = window.location.href
window.location.search()
url.split("?")[1].split("&")
​
//es6 Set Map
const map = new Map()
map.put()
​
const object = {}
object["id"] = 1;

params获取参数

React动态路由参数传递方式

在路由配置的时候,路径上面添加/:name

<Route path="/register/:name/:address" component={Register}></Route>

跳转的时候,需要在路径上面添加数据

<Link to="/register/xiaowang/gaoxin">回到注册</Link>
this.props.push("/register/xiaowang/gaoxin")

在组件中,通过props可以接收到路由的参数

render(){
    console.log(this.props.match.params)
}

这种方式获取到参数,刷新页面,数据还存在。而且路径显示的时候也比较美观

query对象获取参数

传递参数的时候

<Link to={{pathname:"/login",query:{name:"xiaowang",address:"武侯区"}}}>跳转登录</Link>
<button onClick={this.navigateTo}>跳转登录</button>
​
navigateTo = ()=>{
        this.props.history.push({
            pathname:"/login",
            query:{
                name:"xiaofeifei"
            }
        })
    }

获取参数需要通过location对象来获取

this.props.location.query

优点:传递的参数不会显示地址栏,可以传递对象到跳转到组件。

缺点:页面刷新数据会丢失

state的方式传递参数

在传递参数的时候,可以自己定义一个state的对象传递给跳转组件

<Link to={{pathname:"/login",state:{name:"tom"}}}>State的方式跳转登录</Link>

自定义对象属性

Search方式传递参数

可以传递多个参数,需要对参数做一个构造

<Link to="/login?phone=138123456&name=xiaozhang">Search传递参数</Link>

获取参数

this.props.location.search

好处就是:刷新页面数据依然存在,

缺点:参数如果非常多的时候,地址显示非常长

知识点06-路由懒加载

React路由懒加载也是为了提高程序的运行效率。

在React中只要你在组件中,或者在路由中使用import的方式来加载组件,程序在启动的时候,加载你引入组件。

启动的时候花费的时候比较长。

React在以前的老版本里面并没有提供路由懒加载的功能。我们需要使用第三方的懒加载插件,目前React版本里面已经提供了路由懒加载策略。

  1. 基于第三方的懒加载插件完成路由动态加载
  2. 使用React官方提出的懒加载策略

Vue中路由懒加载

component:()=>import ("./Login")

Loadable插件完成

这是一种比较旧的懒加载方式,这种方式作为了解

  1. 下载loadable插件

    yarn add react-loadable
    
  2. 将插件引入到项目中

    import Loadable from "react-loadable"
    const Login = Loadable({
      loader:()=>import("./views/Login"),
      loading:()=><div>...加载中</div>
    })
    const Register = Loadable({
      loader:()=>import("./views/Register"),
      loading:()=><div>...加载中</div>
    })
    const Home = Loadable({
      loader:()=>import("./views/Home"),
      loading:()=><div>...加载中</div>
    })
    

    loader:要加载的组件,import来动态加载

    loading:加载过程执行的动画,你可以封装为一个组件,调用

React推荐的路由懒加载

  1. 使用React官网推荐的组件包裹我们路由器

    <React.Suspense fallback={<Loading></Loading>}>
    <BrowserRouter>
        <Switch>
            <Redirect exact from="/" to="/home"></Redirect>
            <Route path="/login" component={React.lazy(()=>import("./views/Login"))}></Route>
            <Route path="/register" component={React.lazy(()=>import("./views/Register"))}></Route>
            <Route path="/" component={React.lazy(()=>import("./views/Home"))}></Route>
        </Switch>
    </BrowserRouter>
    </React.Suspense>
    

    你需要在路由器组件外面增加一个组件,Suspense,提供一个fallback,当网络加载比较慢的情况下,我们可以提供加载动画,你可以是组件也可以是标签

  2. 使用lazy函数来完成组件的动态加载

    <Route path="/register" component={React.lazy(()=>import("./views/Register"))}></Route>
    

    跟Vue中懒加载很相似,在component加载组件的时候,动态import一次