React 路由

一、SPA的理解

1.单页Web应用(single page web application, SPA)

2.整个应用只有一个完整的页面

3.点击页面中的链接不会刷新页面,只会做页面的局部刷新

4.数据都需要通过ajax请求获取,并在前端异步展现

二、路由的理解

1.什么是路由

  (1)一个路由就是一个映射关系(key:value)

(2)key为路径,value可能是func或者是component

2.路由分类

(1)后端路由:

     1>理解:value是function,用来处理客户端提交的请求

     2>注册路由:router.get(path,function(req,res))

     3>工作过程:当node接受到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回相应数据。

(2)前端路由:

     1>浏览器端路由,value是component,用于展示页面内容

     2> 注册路由:<Route path="/test" component={Test}></Route>

     3>工作过程:当浏览器的path变为/test时,当前路由组件就会变为Test组件

前端路由的工作原理:

History两种工作模式:BrowserHistory,HashHistory

History.createBrowserHistory()直接使用h5推出的history身上的API

History.createHashHistory()  使用hash值(锚点),不会引起页面的刷新,但是可以留下历史记录

3.react-router的理解(web,native,any)

  react-router-dom是专门为web开发人员设计的

(1)react的一个插件库

(2)专门用来实现一个SPA应用

(3)基于react的项目基本都会用到此库

4.react-router相关API

内置组件:

  (1)<BrowserRouter>

  (2)<HashRouter>

  (3)<Route>

    (4)   <Redirect>

  (5)<Link>

  (6)<NavLink>

  (7)<Switch>

其他:

  (1)history对象

  (2)match对象

  (3)withRouter对象

三、路由的使用

1.路由的基本使用

(1)明确好界面中的导航区,展示区

(2)导航区的标签使用Link标签

(3)展示区写Route标签进行路径的匹配

        <Route path="/xxxx" component={demo}/>

(4)<App>的最外层包裹了一个<BrowserRouter>或<HashRouter>

代码示例:

//App.js

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Home from './components/Home'
import About from './components/About'
export default class App extends Component {
  render() {
    return (
      <div>
        <h2>React Router Demo</h2>
        {/* 在React中靠路由实现切换组件  
          <Router>分为BrowserRouter,HashBrowser
        */}
        {/* 编写路由链接 */}
        <Link to="/about">About</Link>
        <Link to="/home">home</Link>
        {/* 注册路由 */}
        <Route path="/about" component={About}/>
        <Route path="/home" component={Home}/>
      </div>
    )
  }
}


// index.js

// 引入React
import React from 'react';
// 引入ReactDOM
import ReactDOM from 'react-dom/client';
import './index.css';
import {BrowserRouter} from 'react-router-dom'
// 引入App组件
import App from './App';


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
     <App />
    </BrowserRouter>
  </React.StrictMode>
);


// About.jsx
import React, { Component } from 'react'

export default class About extends Component {
  render() {
    return (
      <div>
        <h3>我是About的内容</h3>
      </div>
    )
  }
}


// Home.jsx
import React, { Component } from 'react'

export default class Home extends Component {
  render() {
    return (
      <div>
        <h3>我是Home的内容</h3>
      </div>
    )
  }
}

文件目录

2.路由组件与一般组件的区别

(1)写法不同

        一般:<Demo/> 

        路由组件: <Route path="/xxxx" component={demo}/>

(2)存放位置不同

        一般组件:components

        路由组件:pages

(3)接收到的props不同

        一般组件:写组件标签时传递了什么,就能收到什么

        路由组件:接收到三个固定的属性(history、location、match)

3.NavLink与封装NavLink

(1)NavLink可以实现路由链接的高亮,通过activeClassName指定样式名

(2)标签体内容是一个特殊的标签属性

(3)通过this.props.children可以获取标签体内容

添加高亮

<NavLink activeClassName="demo" to="/home">home</NavLink>

封装

// components/MyNavLink

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

export default class MyNavLink extends Component {
  render() {
    return (
      <NavLink activeClassName="demo" {...this.props} />
    )
  }
}

使用

<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
4.Switch的使用

(1)通常情况下,path和component是一一对应的关系

(2)Switch可以提高路由匹配效率(单一匹配)

<Switch>
   <Route path="/about" component={About}/>
   <Route path="/home" component={Home}/>
   <Route path="/home" component={Test}/>
</Switch>
5.解决多级路径刷新页面样式丢失的问题

(1)public/index.html中引入样式不写./写/(常用)

(2)public/index.html中样式时不写./写%PUBLIC_URL%(常用)

(3)使用HashRouter

6.路由的模糊匹配与严格匹配

(1)默认使用的是模糊匹配(输入的路径必须包含要匹配的路径,且顺序要一致)

(2)开启严格匹配

(3)严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由

<Switch>
   <Route exact path="/about" component={About}/>
   <Route exact path="/home" component={Home}/>
</Switch>
7.Redirect的使用

(1)一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由

(2)具体编码:

<Route exact path="/about" component={About}/>
<Route exact path="/home" component={Home}/>
<Redirect to="/about"/>
8.嵌套路由的使用

(1)注册子路由时要写上父路由的path值

(2)路由的匹配时按照注册路由的顺序进行的

// MyNavLink 这个是上面封装的NavLink公共组件,Message和News组件是当做路由组件建立的,里边的内容可以自己定义
<MyNavLink to="/home/message">Message</MyNavLink>
<MyNavLink to="/home/news">News</MyNavLink>
{/* 注册路由 */}
<Switch>
   <Route path="/home/message" component={Message}></Route>
   <Route path="/home/news" component={News}></Route>
   <Redirect to="/home/news"></Redirect>
</Switch>
9.向路由组件中传递params参数

(1)路由链接(携带参数):<Link to={'/home/message/detail/18'}>详情</Link>

(2)注册路由(声明接收):<Route path="/home/message/detail/:id/:title" component={Detail}></Route>

(3)接收参数:const {id, title} = this.props.match.params

文件目录情况:说明:Message是第二层路由,Detail是要展示的具体内容

代码示例:

// Message.jsx
import React, { Component } from 'react'
import Detail from './Detail'
import { Link, Route } from 'react-router-dom'
export default class Message extends Component {
  state = {
    messageArr: [
      {id: '01',title: '消息1'},
      {id: '02',title: '消息2'},
      {id: '03',title: '消息3'},
    ]
  }
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {
            messageArr.map((msgObj) => {
              return (
                <li key={msgObj.id}>
                  {/* 向路由组件传递params参数 */}
                  <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
                </li>
              )
            })
          }
        </ul>
        <hr/>
        {/* 声明接收params参数 */}
        <Route path="/home/message/detail/:id/:title" component={Detail}></Route>
      </div>
    )
  }
}



// Detail.jsx
import React, { Component } from 'react'
const DetailData = [
  {id: '01', content: 'xxxx'},
  {id: '02', content: 'zxxx'},
  {id: '03', content: 'vxxx'},
]
export default class Detail extends Component {
  render() {
    // 接收params参数
    const {id, title} = this.props.match.params
    const finResult = DetailData.find((detailObj) => {
      return detailObj.id === id
    })
    return (
      <div>
        <ul>
          <li>ID:{id}</li>
          <li>Title:{title}</li>
          <li>Content: {finResult.content}</li>
        </ul>
      </div>
    )
  }
}
10.向路由组件中传递search参数

(1)路由链接(携带参数):<Link to={'/home/message/detail/?id=01&title=11'}>详情</Link>

(2)注册路由(无需声明,正常注册路由即可):<Route path="/home/message/detail" component={Detail}></Route>

(3)接收参数:const {search} = this.props.location

  备注:获取到的search是urlencode编码,需要借助querystring解析,目前我使用的版本需要querystring-es3

// Message.jsx
import React, { Component } from 'react'
import Detail from './Detail'
import { Link, Route } from 'react-router-dom'
export default class Message extends Component {
  state = {
    messageArr: [
      {id: '01',title: '消息1'},
      {id: '02',title: '消息2'},
      {id: '03',title: '消息3'},
    ]
  }
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {
            messageArr.map((msgObj) => {
              return (
                <li key={msgObj.id}>
                  {/* 向路由组件传递params参数 */}
                  {/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}

                  {/* 向路由组件传递search参数 */}
                  <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
                </li>
              )
            })
          }
        </ul>
        <hr/>
        {/* 声明接收params参数 */}
        {/* <Route path="/home/message/detail/:id/:title" component={Detail}></Route> */}

        {/* 声明接收search参数(无需声明接收,正常注册路由即可) */}
        <Route path="/home/message/detail" component={Detail}></Route>
      </div>
    )
  }
}


// Detail.jsx
import React, { Component } from 'react'
import qs from 'querystring-es3'

const DetailData = [
  {id: '01', content: 'xxxx'},
  {id: '02', content: 'zxxx'},
  {id: '03', content: 'vxxx'},
]
export default class Detail extends Component {
  render() {
    // 接收params参数
    // const {id, title} = this.props.match.params

    // 接收search参数  ?id =01&title='111'  需要做转换  可以使用querystring库
    const {search} = this.props.location
    const {id, title} = qs.parse(search.slice(1))
    const finResult = DetailData.find((detailObj) => {
      return detailObj.id === id
    })
    return (
      <div>
        <ul>
          <li>ID:{id}</li>
          <li>Title:{title}</li>
          <li>Content: {finResult.content}</li>
        </ul>
      </div>
    )
  }
}
11.向路由组件中传递state参数

(1)路由链接(携带参数):<Link to={{pathname: '/home/message/detail', state:{id:msgObj.id,title:msgObj.title}}>详情</Link>

(2)注册路由(无需声明,正常注册路由即可):<Route path="/home/message/detail" component={Detail}></Route>

(3)接收参数:const {id,title} = this.props.location.state

  备注:刷新也可以保留住参数

代码示例:

// Message.jsx
import React, { Component } from 'react'
import Detail from './Detail'
import { Link, Route } from 'react-router-dom'
export default class Message extends Component {
  state = {
    messageArr: [
      {id: '01',title: '消息1'},
      {id: '02',title: '消息2'},
      {id: '03',title: '消息3'},
    ]
  }
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {
            messageArr.map((msgObj) => {
              return (
                <li key={msgObj.id}>
                  {/* 向路由组件传递params参数 */}
                  {/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}

                  {/* 向路由组件传递search参数 */}
                  {/* <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */}
                  
                  {/* 向路由组件传递state参数 */}
                  <Link to={{pathname: '/home/message/detail', state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link>
                </li>
              )
            })
          }
        </ul>
        <hr/>
        {/* 声明接收params参数 */}
        {/* <Route path="/home/message/detail/:id/:title" component={Detail}></Route> */}

        {/* 声明接收search参数(无需声明接收,正常注册路由即可) */}
        {/* <Route path="/home/message/detail" component={Detail}></Route> */}

        {/* state参数(无需声明接收,正常注册路由即可) */}
        <Route path="/home/message/detail" component={Detail}></Route>
      </div>
    )
  }
}



// Detail.jsx
import React, { Component } from 'react'
// import qs from 'querystring-es3'

const DetailData = [
  {id: '01', content: 'xxxx'},
  {id: '02', content: 'zxxx'},
  {id: '03', content: 'vxxx'},
]
export default class Detail extends Component {
  render() {
    // 接收params参数
    // const {id, title} = this.props.match.params

    // 接收search参数  ?id =01&title='111'  需要做转换  可以使用querystring库
    // const {search} = this.props.location
    // const {id, title} = qs.parse(search.slice(1))


    // 接收state参数
    const {id, title} = this.props.location.state || {}
    const finResult = DetailData.find((detailObj) => {
      return detailObj.id === id
    }) || {}
    return (
      <div>
        <ul>
          <li>ID:{id}</li>
          <li>Title:{title}</li>
          <li>Content: {finResult.content}</li>
        </ul>
      </div>
    )
  }
}
12.编程式路由导航

借助this.props.history对象上的API对操作路由跳转,前进,后退

this.props.history.push()

this.props.history.replace()

this.props.history.goBack()

this.props.history.goForward()

 this.props.history.go()

代码示例:

//message.jsx
import React, { Component } from 'react'
import Detail from './Detail'
import { Link, Route } from 'react-router-dom'
export default class Message extends Component {
  state = {
    messageArr: [
      {id: '01',title: '消息1'},
      {id: '02',title: '消息2'},
      {id: '03',title: '消息3'},
    ]
  }

  replaceShow = (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})
  }
  pushShow = (id,title) => {
    // push跳转,携带params参数
    // this.props.history.push(`/home/message/detail/${id}/${title}`)

    // push跳转,携带search参数
    // this.props.history.replace(`/home/message/detail/?id=${id}&title=${title}`)

    // push跳转,携带state参数
    this.props.history.push(`/home/message/detail`, {id,title})

  }
  back = () => {
    this.props.history.goBack()
  }
  forward = () => {
    this.props.history.goForward()
  }
  go =() => {
    this.props.history.go(2)
  }
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {
            messageArr.map((msgObj) => {
              return (
                <li key={msgObj.id}>
                  {/* 向路由组件传递params参数 */}
                  {/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}

                  {/* 向路由组件传递search参数 */}
                  {/* <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */}
                  
                  {/* 向路由组件传递state参数 */}
                  <Link to={{pathname: '/home/message/detail', state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link>
                  &nbsp;<button onClick={() => this.pushShow(msgObj.id,msgObj.title)}>push查看</button>
                  &nbsp;<button onClick={() => this.replaceShow(msgObj.id,msgObj.title)}>replace查看</button>
                </li>
              )
            })
          }
        </ul>
        <hr/>
        {/* 声明接收params参数 */}
        {/* <Route path="/home/message/detail/:id/:title" component={Detail}></Route> */}

        {/* 声明接收search参数(无需声明接收,正常注册路由即可) */}
        {/* <Route path="/home/message/detail" component={Detail}></Route> */}

        {/* state参数(无需声明接收,正常注册路由即可) */}
        <Route path="/home/message/detail" component={Detail}></Route>

        <button onClick={this.back}>回退</button>
        <button onClick={this.forward}>前进</button>
        <button onClick={this.go}>go</button>
      </div>
    )
  }
}


// Detail.jsx
import React, { Component } from 'react'
// import qs from 'querystring-es3'

const DetailData = [
  {id: '01', content: 'xxxx'},
  {id: '02', content: 'zxxx'},
  {id: '03', content: 'vxxx'},
]
export default class Detail extends Component {
  render() {
    // 接收params参数
    // const {id, title} = this.props.match.params
    
    // 接收search参数  ?id =01&title='111'  需要做转换  可以使用querystring库
    // const {search} = this.props.location
    // const {id, title} = qs.parse(search.slice(1))


    // 接收state参数
    const {id, title} = this.props.location.state || {}
    const finResult = DetailData.find((detailObj) => {
      return detailObj.id === id
    }) || {}
    return (
      <div>
        <ul>
          {/* 路由跳转的push与replace */}
          <li>ID:{id}</li>
          <li>Title:{title}</li>
          <li>Content: {finResult.content}</li>
        </ul>
      </div>
    )
  }
}

13.withRouter的使用

withRouter可以加工一般组件,让一般组件具备路由所持有的API

withRouter的返回值是一个新组件

14.BrowserRouter与HashRouter的区别

(1)底层原理不一样:

        BrowserRouter使用的是H5的history API,不兼容IE9及以下版本

        HashRouter使用的是URL的哈希值

(2)url表现形式不一样

        BrowserRouter的路径中没有#,例如:localhost:3000/demo/test

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

(3)刷新后对路由state参数的影响

        BrowserRouter没有任何影响,因为state保存在history对象中

        HashRouter刷新后会导致路由state参数的丢失

(4)备注:HashRouter可以用于解决一些路径错误相关的问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值