04-React路由5版本(高亮, 嵌套, 参数传递... )

React-Router-Dom(路由版本[5])

简介

  1. React的一个插件库
  2. 用于实现SPA应用
  3. 基于React的项目基本都用

API

  1. <BrowserRouter>
  2. <HashRouter>
  3. <Route>
  4. <Redirect>
  5. <Link>
  6. <NavLink>
  7. <Switch>

其它

  1. history对象
  2. match对象
  3. withRouter函数

添加依赖

yarn add react-router-dom@5

使用

BrowserRouter+Link+Route

import {Link, BrowserRouter, Route} from 'react-router-dom'
// 需要在最外面包裹一个路由管理器 也可以包在index.js的app组件外面
<BrowserRouter>
  <div style={{textAlign: 'center'}}>
    <div>
      {/*定义导航连接*/}
      <Link to="/home">Home</Link>
      <br/>
      <Link to="/about">About</Link>
    </div>
    <div>
      {/*注册路由*/}
      <Route path="/about" component={About}/>
      <Route path="/home" component={Home}/>
    </div>
  </div>
</BrowserRouter>

BrowserRouter+NavLink+Route

和Link功能一样, 但是会在点击的时候自动追加和移除一个class,那就是active, 可以通过属性activeClassName修改

.active {
  background-color: skyblue;
}

就是一个这样的效果

BrowserRouter+NavLink+Switch+Route

主要说一下Switch的用法的作用

import {Link, BrowserRouter, Route, NavLink, Switch} from 'react-router-dom'
<Switch>
  <Route path="/about" component={About}/>
  <Route path="/home" component={Home}/>
  <Route path="/home" component={About}/>
</Switch>

在注册路由时可以使用Switch包裹, 如果不使用, 那么路由匹配遇到相同的, 还会继续往下匹配,并且全部展示

不包裹VS包裹

包裹后, 遇到第一个匹配的路由,就会展示并返回, 不往下继续匹配

样式丢失问题解决[扩展]

index.html

  1. 在引用样式的时候写%PUBLIC_URL%
  2. 使用绝对路径
  3. 使用HashRouter[基本不用]

模糊匹配与精准匹配

默认采用模糊匹配

路由中包含传递的值,即可展示

还是可以展示的,但是路径已经变成了/home/a/b

使用exact={true}可以开启精准匹配

开启精准匹配后再次访问, 就没有展示了

BrowserRouter+NavLink+Switch+Route+Redirect

import {Link, BrowserRouter, Route, NavLink, Switch, Redirect} from 'react-router-dom'
import React, {Component} from 'react';
import {Link, BrowserRouter, Route, NavLink, Switch, Redirect} from 'react-router-dom'
import About from "./components/About";
import Home from "./components/Home";
import './App.css'

class App extends Component {
  render() {
    return (
      // 需要在最外面包裹一个路由管理器 也可以包在index.js的app组件外面
      <BrowserRouter>
        <div style={{textAlign: 'center'}}>
          <div>
            {/*定义导航连接*/}
            <NavLink to="/home">Home</NavLink>
            <br/>
            <NavLink to="/about">About</NavLink>
          </div>
          <div>
            {/*注册路由*/}
            <Switch>
              <Route path="/about" component={About}/>
              <Route path="/home" component={Home}/>
              <Redirect to="/home" />
            </Switch>
          </div>
        </div>
      </BrowserRouter>
    );
  }
}
export default App;

Redirect, 就是重定向的意思, 用于路由中没有匹配到路径的情况, 就会走Redirect重定向到指定路径

输入

默认会中定向到home

嵌套路由使用

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from "react-router-dom";
import News from "../../pages/News";
import Messages from "../../pages/Messages";

class Index extends Component {
  render() {
    return (
      <div>
        <h2>this is home...</h2>
        <div>
          <h4>导航</h4>
          <NavLink to="/home/news">News</NavLink>
          <br/>
          <NavLink to="/home/messages">Messages</NavLink>
        </div>
        <div style={{textAlign: 'center'}}>
          <h4>内容</h4>
          <Route path="/home/news" component={News}/>
          <Route path="/home/messages" component={Messages}/>
        </div>
      </div>
    );
  }
}

export default Index;

在Home组件中继续使用NavLink+Route注册路由, 但是需要携带前缀, 并且在外部不能开启精准模式,不然会造成匹配不到的情况,二级路由也可以使用Redirect实现默认选中

路由组件传递参数[params]

import React, {Component} from 'react';
import {Link, NavLink, Route} from "react-router-dom";
import Detail from "./Detail";

class Index extends Component {
  state = {
    items: [
      {id: '1', name: 'React'},
      {id: '2', name: 'Vue'},
      {id: '3', name: 'Ts'}
    ]
  }

  render() {
    const {items} = this.state
    return (
      <div>
        <ul>
          {
            items.map(item => {
              return (
                <li key={item.id}>
                  {/* 向路由组件传递params参数 */}
                  <Link to={`/home/messages/detail/${item.id}/${item.name}`}>{item.name}</Link>
                </li>
              )
            })
          }
        </ul>
        <hr/>
        {/*接收params参数*/}
        <Route path='/home/messages/detail/:id/:title' component={Detail} />
      </div>
    );
  }
}

export default Index;
import React, {Component} from 'react';

const data = [
  {id: '1', content: 'this is React'},
  {id: '2', content: 'this is Vue'},
  {id: '3', content: 'this is Ts'}
]

class Index extends Component {
  render() {
    const {id, title} = this.props.match.params
    const item = data.filter(x=>x.id===id)[0]
    return (
      <div>
        <div>id:{item.id}</div>
        <div>name:{title}</div>
        <div>content:{item.content}</div>
      </div>
    );
  }
}

export default Index;

通过路径参数传递

路由组件传递参数[search]

{/* 向路由组件传递search参数 */}
<Link to={`/home/messages/detail?id=${item.id}&title=${item.name}`}>{item.name}</Link>
{/*接收search参数 不需要*/}
<Route path='/home/messages/detail' component={Detail}/>
import React, {Component} from 'react';

const data = [
  {id: '1', content: 'this is React'},
  {id: '2', content: 'this is Vue'},
  {id: '3', content: 'this is Ts'}
]

class Index extends Component {
  render() {
    // 接收Params参数
    // const {id, title} = this.props.match.params
    const {id,title} = this.getSearch()
    const item = data.filter(x=>x.id===id)[0]
    return (
      <div>
        <div>id:{item.id}</div>
        <div>name:{title}</div>
        <div>content:{item.content}</div>
      </div>
    );
  }
  // 获取search参数
  getSearch = () => {
    let search = this.props.location.search
    search = search.substring(1);
    let conditions = search.split("&")
    let obj = {}
    conditions.map(condition => {
      const kv = condition.split("=")
      obj[kv[0]] = kv[1]
    })
    return obj
  }
}

export default Index;

在这里 我是自己实现了参数的解析, 也可以使用querystring的方法, 当热这个库在React18之后已经被弃用了, 本来我也想试一下的,但是发现不行

调用直接报错

应该是已经没有依赖了, 可以自己安装一下, 我就不安装了

路由组件传递参数[state(和组件的state没有关系)]

{/* 向路由组件传递state参数[和组件的state没有关系] */}
<Link to={{pathname:'/home/messages/detail',state:{id:item.id,title:item.name}}}>{item.name}</Link>
{/*接收state参数 不需要*/}
<Route path='/home/messages/detail' component={Detail}/>
import React, {Component} from 'react';

const data = [
    {id: '1', content: 'this is React'},
    {id: '2', content: 'this is Vue'},
    {id: '3', content: 'this is Ts'}
]

class Index extends Component {
    render() {
        // 接收Params参数
        // const {id, title} = this.props.match.params
        // 接受Search参数
        // const {id,title} = this.getSearch()
        // 接受state参数
        const {id, title} = this.props.location.state
        const item = data.filter(x=>x.id===id)[0]
        return (
            <div>
                <div>id:{item.id}</div>
                <div>name:{title}</div>
                <div>content:{item.content}</div>
            </div>
        );
    }
    // 获取search参数
    getSearch = () => {
        let search = this.props.location.search
        search = search.substring(1);
        let conditions = search.split("&")
        let obj = {}
        conditions.map(condition => {
            const kv = condition.split("=")
            obj[kv[0]] = kv[1]
        })
        return obj
    }
}

export default Index;

可以直接从location.state上获取, 并且不会在地址栏上显示

replace与push

默认使用push,采用压栈方式存储历史记录, 可以通过back,go来完成前进或者后退

可以修改为replace替换, 默认会替换栈顶部的历史记录, 所以不会留下痕迹, 也就不能通过back,go完成前进和后退

修改方式为, 增加replace属性

编程试路由导航

<Link replace to={{
  pathname: '/home/messages/detail',
  state: {id: item.id, title: item.name}
}}>{item.name}</Link>
<button style={{marginLeft: '5px'}} onClick={event => {
  this.show(item.id, item.name, 'push')
}}>push</button>
  <button style={{marginLeft: '5px'}} onClick={event => {
  this.show(item.id, item.name, 'replace')
}}>replace</button>
<Route path='/home/messages/detail/:id/:title' component={Detail}/>
show = (id, title, type) => {
  // replace | push 路由跳转
  this.props.history[type](`/home/messages/detail/${id}/${title}`)
}

通过props对象上的history对象调用方法实现编程式路由跳转

这个案例是用params参数的方式,如果是search方式就自己改一下问号, 如果是state方式, 就把对象放入参数的第二个参数,第一个是URL, 第二个就是state

路由组件与一般组件

# 直接使用定义的组件 就是一般组件 渲染时props中不会有默认路由组件的三大对象
<Header />
# 通过路由跳转的组件 就是路由组件 渲染时props中会携带 history location match 三大对象
<Route path="/home" component={Home}/>

如果想要在一般组件中使用路由组件的三大对象, 那么就需要withRouter函数

withRouter

import React, {Component} from 'react';
import {withRouter} from "react-router-dom";

class Index extends Component {
  render() {
    console.log(this)
    return (
      <div>
        <h2>this is Header</h2>
      </div>
    );
  }
}

export default withRouter(Index);

这样就可以获取到三大对象了

路由默认入参对象总结

对象

函数/属性

作用

history

go(n)

传入一个number数值,1代表前进一步,-1代表后退一步, 2代表前进两步

goBack()

后退一步

goForward()

前进一步

push(uri, state)

push方式跳转路由, 第一个参数是路由地址, 第二个是state对象

replace(uri,state)

replace方式跳转路由, 第一个参数是路由地址, 第二个是state对象

location

pathname

路由地址

search

search方式传参的获取位置

state

state方式传参的获取位置

match

params

params方式传参的获取位置

path

路由地址

url

路由地址

BrowserRouter和HashRouter的区别

  • 底层原理不一样
    • BrowserRouter使用的是H5的History API不兼容IE9及其以下的版本
    • HashRouter使用的是URL的哈希值
  • URL的表现形式不一样
    • BrowserRouter的路径中没有#, 例如http://localhost:3000/home
    • HashRouter的路径包含#, 例如http://localhost:3000/#/home
  • 刷新后对路由state参数的影响
    • BrowserRouter没有任何影响, 应为state保存在History对象中
    • HashRouter刷新会导致路由state参数的丢失
  • 扩展: HashRouter可以用于解决一些路劲错误相关的问题
posted @ 2022-08-23 16:30  彼岸舞  阅读(116)  评论(0编辑  收藏  举报