react——路由

        前端路由就是把不同路由对应不同的内容或页面对应展示出来。路由可以帮助我们很好的管理页面和代码,增强用户的体验感。路由模式有hash和 history 两种模式,通常用hash模式。在react中,react-router是跨平台的,内置通用组件和通用Hooks。react-router-dom是在react-router基础上提供了Link和NavLink,而且依赖history库提供了两个浏览器端适用的BrowserRouter和HashRouter,现在的项目基本都是使用react-router-dom。本篇文章介绍了使用频率高和我接触到的路由内容。

一、路由原理

        通俗的来说,路由用来管理url地址和视图之间的关系,一个地址对应一个页面要展示的内容,下面展示的地址就是hash模式(/#/)

原理:

​ 1、准备视图(html)

​ 2、准备路由的路线(可以是一个对象,键名是路线名称和值是视图地址)

​ 3、通过hash地址的路线,获取“视图地址”

​ 4、在指定标签中,加载需要的视图页面

原理图灵魂画手

二、使用

(一)安装

npm i react-router-dom@5

(二)导入

import { ...通用组件 } from 'react-router-dom'

(三)使用

   <BrowserRouter >

       <Route path="路径" component={组件}></Route>

    </BrowserRouter >

三、通用组件

(一)BrowserRouter

        history模式,页面跳转原理是使用了pushState、replaceState。使用这个包裹,路由的形式将以/展示,可以通过as重命名,一般见到的形式为:BrowserRouter as Router(把BrowserRouter 重命名为Router )

        属性:

                basename(string):所有位置的基本url,应用是从服务器上的子目录提供的,则需要将其设置为子目录,格式正确的基本名称应以斜杆开头,但不能以斜杆结尾

                getUserConfirmation(fn):用于确认导航的功能,默认使用window.confirm

 <BrowserRouter>

            <Route path='/films' component={Films}></Route>

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

</BrowserRouter>

(二)HashRouter

         hash模式,页面跳转原理是使用了location.hash、location.replace。使用这个包裹,路由的形式将以/#/展示,虽然长的丑,但是用的比较多

<HashRouter>

            <Route path='/films' component={Films}></Route>

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

</HashRouter>

注意:BrowserRouter和HashRouter的区别

1、底层原理不一样

        HashRouter使用的是Url的哈希值

        BrowserRouter使用的是h5的history api,不兼容ie9及以下版本

2、path表现形式不一样HashRouter带个#号

3、HashRouter刷新后对路由state参数的影响,而BrowserRouter是将state保存再history对象中

4、HashRouter可以用于解决一些路径错误相关的问题

(三)Route

        匹配组件,并展示组件。即匹配成功后,组件立即被替换成匹配的组件

属性 类型 作用
path str | obj 路由匹配路径,没有path属性的Route总是会匹配
exact bool 为true时,要求全路径匹配(/home)。路由默认为“包含”的(/和/home)都匹配,这意味着多个Route可以同时进行匹配和渲染
component fn | component 在地址匹配的时候React的组件才会被渲染,route props也会随着一起被渲染
render func 内联渲染和包装组件,要求要返回目标组件的使用

<Route path='/films' component={Films} />

或者

 <Route path="/" exact render={() => {
        return <IndexPage user={user} />
  }} />
 

注意:模糊匹配和精准匹配

        因为exact的存在,分为模糊匹配和精准匹配

(四)Switch

        排他性(单一)匹配。如果不想使用包容性,那么使用Switch,类似于js中的switch分支语句,被包裹在里面的组件会被匹配到一个,并跳出结束,常用于侧边栏,引导选项卡

属性 类型 作用
location str | obj

一般我们不会给该组件设置 location 属性。 

不设置: Switch组件的子组件(一般是 Route 或 Redirect)会根据当前浏览器的 location 作为匹配依据來进行路由匹配。
设置: Switch 组件的子组件会根据定义的 location 作为匹配依据

  <HashRouter>

                {/* Switch类似于Js里面的Switch分支,被包裹的相当于case,总能匹配到一个,并跳出 */}

                {/* 这样能做到一个页面出出现一个,不会多个页面展示在一个页面中 */}

                <Switch>

                    <Route path='/films' component={Films}></Route>

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

                </Switch>

  </HashRouter>

(五)Redirect

        重定向,如用户输入了/,见到/会指定跳转到重新定义的页面,在这里使用了exact,功能精准匹配,只有看到单独是/的才会重定向。模糊匹配,只要含有/就会响应

属性 类型 作用
from string 来自
to string object 去向
push boolean 添加历史记录
exact boolean 严格匹配
sensitive boolean

区分大小写

 <HashRouter>

            <Route path='/films' component={Films}></Route>

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

            {/* 模糊匹配 */}

            {/* <Redirect from='/' to='/home'/> */}

            {/* 精准匹配 */}

            <Redirect from='/' to='/home' exact/>

</HashRouter>

温馨提示:如果没有子路由的情况,建议大家配都加一个exact;如果有子路由,建议在子路由中加exact,父路由不加; 而strict是针对是否有反斜杠的,一般可以忽略不配置

(六)Link

        相当于a标签,在react将虚拟DOM渲染成真实DOM后,Link组件也被渲染成了a标签,常用于导航

属性 类型 作用
to str | obj{pathname:,search:,hash:} 要跳转的路径或地址
replace bool 是否替换历史记录

 <ul>

            <li>

                <Link to='/films'>电影</NavLink>

            </li>

            <li>

            <Link to='/cimans'>影院</NavLink>

            </li>

            <li>

            <Link to='/home'>我的</NavLink>

            </li>

</ul>

(七)NavLink

        NavLink方式相当于Link的加强版

属性 类型 作用
to str | obj{pathname:,search:,hash:} 要跳转的路径或地址
replace bool 是否替换历史记录
 activeClassName str 设置选中样式,默认值为active
activeStyle obj 当元素被选中时,为此元素添加样式
 exact bool 为true时,只有当导致和完全匹配class和style才会应用
strict bool 为true时,在确定为位置是否与当前URL匹配时,将考虑位置pathname后的斜线
isActive fun 判断链接是否激活的额外逻辑的功能

 <ul>

            <li>

                <NavLink to='/films'>电影</NavLink>

            </li>

            <li>

                    <NavLink to='/cimans'>影院</NavLink>

            </li>

            <li>

                    <NavLink to='/home'>我的</NavLink>

            </li>

</ul>

(八)withRouter

       将一个组件包裹进Route里面, 然后react-router的三个对象history, location, match就会被放进这个组件的props属性中.

// withRouter实现原理: 
// 将组件包裹进 Route, 然后返回
// const withRouter = () => {
//     return () => {
//         return <Route component={Nav} />
//     }
// }

// 这里是简化版
const withRouter = ( Component ) => () => <Route component={ Component }/>
//withRouter的返回值是一个新组件

        如果我们某个东西不是一个Router, 但是我们要依靠它去进行浏览记录的前进后退 这时候就可以使用withRouter,将一般组件变成路由组件。使用场景:比如点击页面的logo, 返回首页, 这时候就可以使用withRouter来做

import React, { Component } from 'react'
import {withRouter} from 'react-router-dom' //引入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的返回值是一个新组件

三、通用Hooks

使用在5.1版本及之后,并且是函数式组件中才可以使用,使用见第四点传参时候的代码演示

(一)useHistory 

获取History对象。访问history对象,进行编程式的导航

//导入

import {useHistory } from "react-router-dom"

const Home = () => {
  return (
    <div>Home</div>
  )
}
const Detail = () => {

//使用

 const history = useHistory()

console.log("history",history);//获取History对象

console.log("获取当前页路径",history.location.pathname);//获取当前页路径

//和下面通过js获取一致

console.log(props.location.pathname);

  return (
    <div>

      <-- 使用-->
      <button onClick={() => { history.push('/')}}>go home</button>
    </div>
  )
}
function App() {
  return (
    <div className="App">
      <Router>
        <Switch>
          <Route exact path="/" component={Home}/>
          <Route path="/detail/:id" component={Detail}/>
        </Switch>
      </Router>
    </div>
  );
}

(二)useLocation 

获取Location对象。在各层组件中,轻松获取location对象。在V5.1版本之前,我们需要使用props.location。而对于更深层的组件,还需要使用withRouter

//导入

import {

  useLocation 

 } from "react-router-dom";

//使用

    const location = useLocation ()

    console.log("location",location);

(三)useParams 

获取路由参数的键值对的对象,访问当前的<Route>的match.params。在V5.1版本之前,我们需要通过props.match获取路由参数。对于更深层的组件还需要使用高阶组件withRouter

//设置<Route>的match.params
        <Router>
            <Switch>
                <Route path="/:path">
                    <Home></Home>
                </Route>
            </Switch>
        </Router>

//获取

  let { path } = useParams();

  console.log("path ",path );

(四)useRouteMatch 

useRouteMatch,接受一个path字符串作为参数。当参数的path与当前的路径相匹配时,useRouteMatch会返回match对象,否则返回null。

useRouteMatch在对于一些,不是路由级别的组件。但是组件自身的显隐却和当前路径相关的组件时,非常有用。

比如,你在做一个后台管理系统时,网页的Header只会在登录页显示,登录完成后不需要显示,这种场景下就可以用到useRouteMatch

const Home = () => {
  return (
    <div>Home</div>
  )
}
// Header组件只会在匹配`/detail/:id`时出现
const Header = () => {
  // 只有当前路径匹配`/detail/:id`时,match不为null
  const match = useRouteMatch('/detail/:id')
  return (
    match && <div>Header</div>
  )
}
const Detail = () => {
  return (
    <div>Detail</div>
  )
}
function App() {
  return (
    <div className="App">
      <Router>
        <Header/>
        <Switch>
          <Route exact path="/" component={Home}/>
          <Route exact path="/detail/:id" component={Detail}/> 
        </Switch>
      </Router>
    </div>
  );
}

(五)useRoutes

路由表,钩子在useRoutes功能上等同于<Routes>,但它里面使用 JavaScript 对象而不是<Route>元素来定义您的路由

  • useRoutes()的参数为数组。

  • useRoutes的返回值要么是可用于渲染路由树的有效 React 元素,要么null是不匹配的元素。

  • 嵌套路由用 children 实现。

使用useRoutes实现:

import * as React from "react";
import { useRoutes } from "react-router-dom";

function App() {
  let element = useRoutes([
    {
      path: "/",
      element: <Dashboard />,
      children: [
        {
          path: "messages",
          element: <DashboardMessages />,
        },
        { path: "tasks", element: <DashboardTasks /> },
      ],
    },
    { path: "team", element: <AboutPage /> },
  ]);

  return element;
}

使用Routes和Route实现:

<Routes>
  <Route path="/" element={<Dashboard />}>
    <Route
      path="messages"
      element={<DashboardMessages />}
    />
    <Route path="tasks" element={<DashboardTasks />} />
  </Route>
  <Route path="about" element={<AboutPage />} />
</Routes>

四、路由传参

在v5.x中只有编程式的获取参数方式,在v5.1及之后增加了Hooks后,既可以用编程式的方式获取url携带的参数,也可以使用Hooks中的方法来获取(只能是函数式组件),前面一种也成为显式传参,后面两种成为隐式传参

(一)params参数

1、注册路由

//注册路由

<Route path="/details/:name/:age" component={Details}/>

2、路由跳转

//路由跳转

<Link to='/details/tom/18'}>详情</Link>

 <button onClick={()=>{props.history.push('details/tom/18')}}>去详情页</button>

3、在详情页获取参数

//在详情页获取参数

 console.log(props.match.params);

import { useParams } from "react-router-dom";

const params = useParams();

(二)search参数

1、注册路由

//注册路由

<Route path="/details" component={Details}/>

2、路由跳转

//路由跳转

<Link to='/details/tom/18'}>详情</Link>

 <button onClick={()=>{props.history.push('details?name=tom&age=18')}}>去详情页</button>

3、在详情页获取参数 

//在详情页获取参数 

console.log(props.location.search);//拿到的是?id=1&age=18,

import { useParams } from "react-router-dom";

const params = useParams();拿到的是?id=1&age=18

在以上两种方式中,获取到的search是urlencoded编码字符串,需要借助query-string解析参数成对象或者自己封装一个截取的工具函数

 const { search } = props.location

const { num } = qs.parse(search.slice(1))

(三)state参数

1、注册路由

//注册路由

<Route path="/details" component={Details}/>

2、路由跳转

//路由跳转

<Link  to={ {

        pathname:'/detils',

        state:{

                id:1,

                age:18

        }

}} > 去详情页 </Link>

 <button onClick={()=>{props.history.push({

            pathname:'/details',

            state:{

                id:1,

                age:18

            }

})}}>去详情页</button>

3、在详情页获取参数 

//在详情页获取参数 

console.log(props.history.location.state);//{id: 1, age: 18}

import { useLocation  } from "react-router-dom";

const { state } = useLocation();

console.log(state);//{id: 1, age: 18}

猜你喜欢

转载自blog.csdn.net/m0_55173487/article/details/128618909