React路由的跳转和传参数

4,855 阅读6分钟

<一> 链接的跳转方式

一: Link和NavLink的跳转方式

LinkNavLink用法一样,不用之处在于NavLinkactiveClassName属性,用于设置当前活动的tab标签的样式,以下是对NavLink的使用说明。

1) index.js入口文件文件

由于路由跳转(LinkNavList)和路由注册都需要 BrowserRouter包裹,所以为了能够全局使用路由,我们需要在入口写入用BrowserRouter包裹App组件。

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./index.css";
ReactDOM.render(
    <BrowserRouter>
         <App/>
    </BrowserRouter>
,document.getElementById('root'))

2) App组件文件

import React,{ Component } from "react";
import Main from "./components/Main";
import "./App.css";
export default class App extends Component {
    render(){
        return (
            <div className="app">
                <Main></Main>
            </div>
        )
    }
}

3) Main组件文件

import React,{ Component } from "react";
import NavList from "../NavList";
import Center from "../Center";
import "./index.css";
export default class Main extends Component {
    render() {
        return (
            <div className="main">
                <NavList ></NavList>
                <Center ></Center>
            </div>
        )
    }
}

4) NavList组件文件

在此项目中,我们是在此文件定义路由的跳转。我们使用的是NavLink 其中activeClassName="active"active是我们自己定义的样式,即当前活动路由的tab样式。路由的路劲使用to="/home",其中/home就是我们要跳转的路由路劲。

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

import "./index.css";
export default class NavList extends Component {
    render() {
        return (
            <div className="navList">
                <h1>NavList组件</h1>
                <div className="list-group">
                    <NavLink activeClassName="active" className="list-group-item " to="/home">Home</NavLink>
                    <NavLink activeClassName="active" className="list-group-item" to="/about">About</NavLink>
                </div>

            </div>
        )
    }
}

5)Center组件文件

上面我们已经写好了路由的跳转,但还需要注册路由表,该项目是在此文件写路由表的。路由表的注册使用的是Route 标签,路由使用的是path='/home',其中/home就是我们的路由路劲。component是我们路由跳转需要展示的组件。一般路由组件我们是写在pages目录下的。

import React,{ Component } from "react";
import { Route } from "react-router-dom";
import Home from "../../pages/Home";
import About from "../../pages/About";
import "./index.css";
export default class Center extends Component {
    render() {
        return (
            <div className="center">
                <h1>Center组件</h1>
                <Route path='/home' component={Home}></Route>
                <Route path='/about' component={About}></Route>
            </div>
        )
    }
}

注意:

  • 路由组件可以获取通过this.props获取路由相关信息,普通组件是不可以的。
  • 路由组件是需要赋给component属性,而不能直接写标签。
  • 路由组件一般我们都是写在pages目录下

二:对NavLink的封装

由于NavLink需要的一些属性都差不多,所以我们可以对它进行封装,没必要每次都需要些冗余的代码。

由以下例子可知,NavLink需要的公共属性有activeClassNameclassName

<NavLink activeClassName="active" className="list-group-item " to="/home">Home</NavLink>

1)MyNavList组件文件

NavLink的封装后,代码如下:

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

import "./index.css";
export default class MyNavList extends Component {
    render() {
        return (
            <NavLink activeClassName="active" className="list-group-item " {...this.props}/>      
        )
    }
}

2)使用MyNavList组件

import React,{ Component } from "react";
import MyNavLink from "../MyNavLink";

import "./index.css";
export default class NavList extends Component {
    render() {
        return (
            <div className="navList">
                <h1>NavList组件</h1>
                <div className="list-group">
                    {/* 路由跳转 */}
                    <MyNavLink to="/home">首页</MyNavLink>
                    <MyNavLink to="/about">关于</MyNavLink>
                </div>

            </div>
        )
    }
}

三:Switch的使用

在注册路由表的时候,使用Switch标签,当匹配到指定路由后,就不继续往下匹配,提高效率。

import React,{ Component } from "react";
import { Route,Switch } from "react-router-dom";
import Home from "../../pages/Home";
import About from "../../pages/About";
import "./index.css";
export default class Center extends Component {
    render() {
        return (
            <div className="center">
                <h1>Center组件</h1>
                {/* 注册路由,使用Switch标签,当匹配到指定路由后,就不继续往下匹配,提高效率 */}
                <Switch>
                    <Route path='/home' component={Home}></Route>
                    <Route path='/about' component={About}></Route>
                </Switch>
                
            </div>
        )
    }
}

四:开启模糊模式(默认)和启精准匹配(严格匹配)

默认是模糊匹配 exact=false

模糊匹配:输入的路由必须包含注册路由的路劲,输入的可以比注册的多,但路劲的顺序必须一样 。比如:注册路由是/home,但我输入的路劲是/home/a在模糊匹配下,页面正常显示,而/b/home/a则不能正常显示。

<Switch>
   <Route path='/home' component={Home}></Route> // 模糊模式
   <Route exact path='/about' component={About}></Route> // 严格模式
</Switch>

注意:

  • 一般我们不使用严格模式,而采用的是模糊匹配。在开启严格模式下,不能创建子路由(路由嵌套)

五:路由重定向

Redirect一般放在路由表的最下方。当我们输错或者开启默认打开的是路由/home

<Switch>
  <Route path='/home' component={Home}></Route>
  <Route exact path='/about' component={About}></Route>
  <Redirect to="/home" />
</Switch>

六:子路由

用法一样,不同之处在于子路由表必须包含父路由表。本例子父路由表是/home,那么子路由表是/home/news/home/news

import React,{ Component } from "react";
import MyNavLink from "../../components/MyNavLink";
import { Route,Redirect } from "react-router-dom";

import News from "./News";
import Message from "./Message";
import "./index.css"
export  default class Home extends Component {
  render() {
      return (
          <div>
              Home.....
              <div>
                  <ul className="tab-group">
                      <li className="tab-group-item">
                          <MyNavLink to="/home/news">新闻</MyNavLink>
                      </li>
                      <li className="tab-group-item">
                          <MyNavLink to="/home/message">消息</MyNavLink>
                      </li>
                  </ul>
                  {/* 这里是注册子路由表 */}
                  <Route path="/home/news" component={News}/>
                  <Route path="/home/message" component={Message}/>
                  <Redirect to="/home/news"/>
              </div>
          </div>
      )
  }
}

七:路由传递参数

1) 路由跳转文件

import React,{ Component } from "react";
import {Link } from "react-router-dom";
export  default class MessageTab extends Component {
  state = {
      tabList: [
          {
              title: "美国最新消息",
              id: '1'
          },
          {
              title: "中印外交最新消息",
              id: '2'
          },
          {
              title: "最新疫情消息",
              id: '3'
          }
      ]
  }
  render() {
      let {tabList} = this.state
      return (
          <ul>
              {
                  tabList.map(tabItem => {
                      return (
                          <li key={tabItem.id}>
                              {/* 跳转路由,并向路由组件传递params参数 */}
                              {/* <Link to={`/home/message/tab/${tabItem.id}`}>{tabItem.title}</Link> */}

                              {/* 跳转路由,并向路由组件传递search参数 */}
                              {/* <Link to={`/home/message/tab/?id=${tabItem.id}`}>{tabItem.title}</Link> */}


                               {/* 跳转路由,并向路由组件传递state参数 */}
                               <Link to={{pathname:`/home/message/tab`,state:{id:tabItem.id}}}>{tabItem.title}</Link>
                          </li>
                      )
                  })
              }
          </ul>
      )
  }
}

2)路由表的注册


import React,{ Component } from "react";
import {Route } from "react-router-dom";
import MessageTab from "./MessageTab";
import MessageDetail from "./MessageDetail";
import "./index.css"
export  default class Message extends Component {
  render() {
      return (
          <div>
              <MessageTab/>
              {/* 注册路由,声明接收params参数 */}
              {/* <Route path="/home/message/tab/:id" component={MessageDetail}/> */}

              {/* 注册路由,声明接收search参数 */}
              {/* <Route path="/home/message/tab" component={MessageDetail}/> */}

              {/* 注册路由,声明接收state参数 */}
              <Route path="/home/message/tab" component={MessageDetail}/>
          </div>
      )
  }
}

3)路由组件接收参数

import React,{ Component } from "react";
import qs from "querystring";
export  default class MessageDetail extends Component {
  render() {
      /* 接收 params参数 */
      //   let {match:{params:{id}}} =  this.props

      /* 接收search参数 */
      // let {id} = qs.parse(this.props.location.search.substring(1))

      /* 接收state参数 */
      console.log(this.props)
      let {location:{state:{id}}} = this.props
      return (
         <div>
             消息详情{id}
         </div>
      )
  }
}

<二> 编程式导航

除了链接方式的跳转,react-touter还提供了一些API,方便使用js的方式去做路由的跳转。路由表注册、路由组件接收参数和普通的链接跳转方式是一样的。

  • withRouter

    将普通组件封装,返回成类似于路由组件,能使用路由提供的一些API

    对于路由组件,我们是可以直接使用路由的一些API的,例如以下的API:

    this.props: {
    
      history: {
        action: "PUSH"
        block: ƒ block(prompt)
        createHref: ƒ createHref(location)
        go: ƒ go(n)
        goBack: ƒ goBack()
        goForward: ƒ goForward()
        length: 50
        listen: ƒ listen(listener)
        location: {pathname: "/home/message/tab/", search: "", hash: "", state: {…}, key: "mdz00e"}
        push: ƒ push(path, state)
        replace: ƒ replace(path, state)
      },
      
      location: {
        hash: ""
        key: "yarub9"
        pathname: "/home/message/tab/"
        search: ""
        state: {id: "3"}
       },
       
       match: {
          sExact: false
          params: {}
          path: "/home/message"
          url: "/home/message"
       }
    }
    

    分析:

    • go: ƒ go(n)nnumber类型。正数表示的是前进n步,负数表示后退n步。
    • goBack: ƒ goBack()。表示回退。
    • goForward: ƒ goForward()。表示前进。
    • push: ƒ push(path, state)。表示压栈,有记录。
    • replace: ƒ replace(path, state)。表示替换当前路由。

    由于messageTab组件是普通组件,我们要想使用编程式路由导航,我们就需要引入withRouter。通过export default withRouter(MessageTab)暴露出去。

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

     class MessageTab extends Component {
        state = {
            tabList: [
                {
                    title: "美国最新消息",
                    id: '1'
                },
                {
                    title: "中印外交最新消息",
                    id: '2'
                },
                {
                    title: "最新疫情消息",
                    id: '3'
                }
            ]
        }
        showMessageDetail = (tabItem)=> {
            return ()=> {
                /* push模式--传递params参数 */
                // this.props.history.push(`/home/message/tab/${tabItem.id}`)


                 /* push模式--传递search参数 */
                //  this.props.history.push(`/home/message/tab/?id=${tabItem.id}`)

                  /* push模式--传递state参数 */
                  this.props.history.push(`/home/message/tab/`,{id:tabItem.id})

            }
        }
        render() {
            let {tabList} = this.state
            return (
                <ul>
                    {
                        tabList.map(tabItem => {
                            return (
                                <li key={tabItem.id}>
                                    {/* 跳转路由,并向路由组件传递params参数 */}
                                    {/* <Link to={`/home/message/tab/${tabItem.id}`}>{tabItem.title}</Link> */}

                                    {/* 跳转路由,并向路由组件传递search参数 */}
                                    {/* <Link to={`/home/message/tab/?id=${tabItem.id}`}>{tabItem.title}</Link> */}


                                     {/* 跳转路由,并向路由组件传递state参数 */}
                                     {/* <Link to={{pathname:`/home/message/tab`,state:{id:tabItem.id}}}>{tabItem.title}</Link> */}

                                     {/* 编程式导航 */}
                                     <div onClick={this.showMessageDetail({id:tabItem.id})}>
                                        {tabItem.title}
                                     </div>
                                </li>
                            )
                        })
                    }
                </ul>
            )
        }
    }
    export  default withRouter(MessageTab)

<三> BrowserRouter和HashRouter的区别

    1. 底层原理不一样:
    • BrowserRouter使用的是H5的````history``` API
    • HashRouter使用的是URL的哈希值。
    1. url表现形式不一样:
    • BrowserRouter的路由中没有#符号
    • HashRouter的路由中有#符号
    1. 刷新后对路由state参数的影响:
    • BrowserRouterstate参数没有任何影响,因为state保存在history对象中,只要浏览器不清空缓存数据或关闭
    • HashRouterstate参数有任何影响,state参数丢失。