React路由

Posted _洋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React路由相关的知识,希望对你有一定的参考价值。

文章目录

单页面应用spa

多页面应用是指每切换一个页面就是一个真正的html页面。
单页面应用是指整个应用只有一个完整的页面,点击页面中的链接不会刷新页面只会局部更新,并且数据都需要通过ajax请求获取,并在前端异步展示。

单页面,多组件。

路由

路由是什么

  1. 什么是路由? —— Route
    —个路由就是一个映射关系 ( key:value )
    key为路径, value 可能是function(后端路由)或component(前端路由)路由分类
  • 后端路由:
    理解:value是function,用来处理客户端提交的请求。
    注册路由: router.get(path, function(req, res))
    工作过程:当node接收到一个请求时,根据请求路径找到匹配的路由,调用路
    由中的函数来处理请求返回响应数据
  • 前端路由:
    浏览器端路由,value是component,用于展示页面内容。
    注册路由: <Route path="/test" component=Test>
    工作过程:当浏览器的path变为/test时,当前路由组件就会变为Test组件
  1. 路由器 —— Router
    路由器是用于管理路由的。

React路由原理


路由匹配的是只是端口号后面的内容(/about、/history)。

点击页面选项路径改变

那么是如何实现一点击导航栏的选项浏览器地址栏中的路径就改变呢, 这就需要借助history实现。
浏览器的BOM身上有一个history,用于管理浏览器的路径、历史记录等。
但是BOM原生的history不好操作我们一般用一个封装好的库history.js,(该库实际上操作的也是BOM身上的history)引入:

<script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>

,使用:

  1. 引入:
let history = History.createBrowserHistory()
  1. 推入
// 将路径放到历史记录history中
	history.push(path)
  1. 替换
// 将路径放到历史记录history中
	history.replace(path)
  1. 监听路径变化
// history的listen方法可以监听路径的修改
	history.listen((location) => 
		console.log('请求路由路径变化了', location)
	)
  1. 前进
	history.goForward()
  1. 后退
	history.goBack()

history的数据结构是栈结构:

栈顶的路径就是当前页面显示的内容。

History.createBrowserHistory()是使用的是h5身上的history方法,在某些旧的浏览器不支持。
可以使用: History.createHashHistory(),和createBrowserHistory的区别是路径中会多出一个 # ,虽然不好看但是兼容性特别好。

History.createBrowserHistory():

History.createHashHistory():

路径改变页面变化

React会监听路径,当路径发生变化时,被前端路由器检测到,就会进行路由匹配重新渲染页面。

React路由的使用

React路由的实现需要借助react的路由插件库:react-router-dom, 专门用于实现SPA应用。

  • 安装:
npm i react-router-dom

实现点击页面选项路径改变——编写路由链接

直接利用从 react-router-dom 库中引入的路由器Router</Link>标签就可以实现:

import  BrowserRouter, Link  from 'react-router-dom'

<BrowserRouter>
    <Link className="list-group-item" to="/about">About</Link>
    <Link className="list-group-item" to="/home">Home</Link>
 </BrowserRouter>

点击About浏览器的路径就变成 /about, 点击Home浏览器的路径就变成/home

有两种Router标签:<BrowserRouter> 和 <HashRouter>,在Router标签中再使用<Link>进行路由。
<BrowserRouter> 标签就对应history的browser模式
<HashRouter> 标签就对应history的hash模式

(最后在浏览器渲染的时候,Link标签实际上是会转换为a标签的)

根据路径显示组件 ——注册路由

直接利用从 react-router-dom 库中引入的路由Route 进行路由的注册:

   import  Route  from 'react-router-dom'
/* 注册路由 */
  	<Route path="/about" component=About/>
    <Route path="/home" component=Home/>

<Route > 也需要使用Router标签进行包裹,但是编写路由链接的路由器应该和注册路由的路由器是一个路由器才对,可以直接将<App/>组件使用Router标签包裹即可。

index.js

// 引入react核心库
import React from 'react'
// 引入ReactDOM
import ReactDOM from 'react-dom'
// 引入路由组件
import  BrowserRouter  from 'react-router-dom'
// 引入App组件
import App from './App'

// 渲染App到页面
ReactDOM.render(
   <BrowserRouter>
       <App/>
   </BrowserRouter>, 
   document.getElementById('root'))

组件的分类——普通组件和路由组件

像上面的例子通过路由来使用组件:<Route path="/about" component=About/>,这样的组件叫做路由组件。还有一类就是通过标签正常使用的组件如<About/>,这样的组件就是普通组件。
普通组件一般直接放在src/component文件夹中,路由组件一般放在src/pages中。

普通组件和路由组件一个最大的区别就是,路由组件可以接收到路由器传递的参数。如当点击上述例子的About按钮时,接收到的参数为:

  • history :
    go:可以穿参数n,表示前进或后退|n|步,n>0表示前进n步,n<0表示后退n步。
    goBack:后退1步
    goForward:前进1步
    push:push路由
    replace:replace路由
    location:(和下面的这个location是同一个对象)
  • location
    pathname:获取路由路径
    search:(存储swarch参数)
    state:(存储state参数)
  • match
    params:(存储params参数)
    path:获取路由路径
    url:获取路由路径

案例

实现效果:


代码:


src/index.js

// 引入react核心库
import React from 'react'
// 引入ReactDOM
import ReactDOM from 'react-dom'
// 引入路由组件
import  BrowserRouter  from 'react-router-dom'
// 引入App组件
import App from './App'

// 渲染App到页面
ReactDOM.render(
    <BrowserRouter>
        <App/>
    </BrowserRouter>, document.getElementById('root'))


src/App.jsx

import React,  Component  from 'react'
import   Link, Route  from 'react-router-dom'

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
export default class App extends Component 
  render() 
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              /* 原生直接使用a标签进行切换 */
              /* <a className="list-group-item active" href="./about.html">About</a>
              <a className="list-group-item" href="./home.html">Home</a> */

              /* react中靠路由链接进行切换 */
              /* 
                有两种Router:
                  <BrowserRouter>
                  <HashRouter>
                  再Router标签中再使用Link进行路由
               */
                  <Link className="list-group-item" to="/about">About</Link>
                  <Link className="list-group-item" to="/home">Home</Link>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                /* 注册路由 */
                <Route path="/about" component=About/>
                <Route path="/home" component=Home/>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  


page/About/index.jsx

import React,  Component  from 'react'

export default class About extends Component 
  render() 
    console.log("接收到参数:", this.props);
    return (
      <div>About ... </div>
    )
  


page/Home/index.jsx

import React,  Component  from 'react'

export default class Home extends Component 
  render() 
    return (
      <div>Home ... </div>
    )
  


components/Header/index.jsx

import React,  Component  from 'react'

export default class index extends Component 
  render() 
    return (
        <div className="row">
            <div className="col-xs-offset-2 col-xs-8">
                <div className="page-header"><h2>React Router Demo</h2></div>
            </div>
        </div>
    )
  


实现选中高亮效果——NavLink

需要借助 <NavLink><NavLink/>实现, <NavLink> 标签配合 activeClassName='类名' 实现,当点击该标签 该样式就会显示。

activeClassName='类名'中的类名默认是active。
eg:
上述案例修改App.jsx

import React,  Component  from 'react'
import   NavLink, Route  from 'react-router-dom'

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
export default class App extends Component 
  render() 
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
                  <NavLink activeClassName='active' className="list-group-item" to="/about">About</NavLink>
                  <NavLink activeClassName='active' className="list-group-item" to="/home">Home</NavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                /* 注册路由 */
                <Route path="/about" component=About/>
                <Route path="/home" component=Home/>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  


效果:

注意:这里我在public文件夹中已经引入了bootstrap.css样式,所以会有样式效果

NavLink的封装

知识点:

  • 组件标签的标签体中的内容会作为children属性传递给组件
  • 在组件中通过children属性就可以指定标签体的内容。

即:
App.jsx

import React,  Component  from 'react'
import  Route  from 'react-router-dom'

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
import MyNavLink from './components/MyNavLink'
export default class App extends Component 
  render() 
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
                    /* 标签体中的内容会作为children属性传递给组件 */
                  <MyNavLink to="/home">Home</MyNavLink>
                  <MyNavLink to="/about">About</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                /* 注册路由 */
                <Route path="/about" component=About/>
                <Route path="/home" component=Home/>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  


MyNavLink,jsx

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

export default class MyNavLink extends Component 
  render() 
    return (
        <NavLink activeClassName='active' className="list-group-item" ...this.props/>
    )
  


Switch的使用

一般情况下一个路径(path)只对应一个组件,如果一个路径对应多个组件会是什么效果呢,答案是多个组件都会显示,如:

<div className="col-xs-6">
   <div className="panel">
     <div className="panel-body">
       /* 注册路由 */
       <Route path="/about" component=About/>
       <Route path="/home" component=Home/>
       <Route path="/home" component=Test/>
     </div>
   </div>
 </div>

显示如下:

说明当路径匹配完成之后如果再出现同样的路径就会再次匹配,但是一般情况下一个路径对应一个组件就可以了,所以说为了提升效率,我们希望当匹配到一个路径之后,再碰到该路径就不会进行匹配了。这就可以借助<Switch>组件,用<Switch>组件包裹路由。

import  Route, Switch  from 'react-router-dom'

<div className="col-xs-6">
   <div className="panel">
     <div className="panel-body">
       /* 注册路由 */
       <Switch>
         <Route path="/about" component=About/>
         <Route path="/home" component=Home/>
         <Route path="/home" component=Test/>
       </Switch>
     </div>
   </div>
 </div>

补充:样式丢失问题

启动React脚手架,浏览器访问http://localhost:3000/favicon.ico,代表访问public文件夹下的favicon.ico资源。即本地服务器的根路径就是/public文件夹,如果/public文件夹中没有对应的资源就会返回/public/index.html内容。

当路由路径是多级路径,并且刷新页面的时候就会出现样式丢失。因为他会把一级路由放在请求路径进行请求。
eg:
app.jsx

import React,  Component  from 'react'
import  Route, Switch  from 'react-router-dom'

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
import MyNavLink from './components/MyNavLink'
export default class App extends Component 
  render() 
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
                    /* 标签体中的内容会作为children属性传递给组件 */
                  <MyNavLink to="/yang/home">Home</MyNavLink>
                  <MyNavLink to="/yang/about">About</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                /* 注册路由 */
                <Switch>
                  <Route path="/yang/about" component=About/>
                  <Route path="/yang/home" component=Home/>
                </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  


浏览器:

解决·:

  • 法一: index.html中引入样式的时候使用相对路径:
<link rel="stylesheet" href="/css/bootstrap.css">
  • 法二: 使用 %PUBLIC_URL%%PUBLIC_URL% 代表的是public文件夹的绝对路径
<link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">
  • 法三:使用HashRouter而不是BrowserRouter。
    index.jsx
// 引入react核心库
import React from 'react'
// 引入ReactDOM
import ReactDOM from 'react-dom'
// 引入路由组件
import  HashRouter  from 'react-router-dom'
// 引入App组件
import App from './App'

// 渲染App到页面
ReactDOM.render(
    <HashRouter>
        <App/>
    </HashRouter>, document.getElementById('root'))

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

模糊匹配

一般情况下:NavLinkto 属性和Routepath属性匹配到的路径是一样的。
NavLinkto 属性是多级路由,但是Routepath只是匹配到第一级路由,那么组件会进行展示;
但是如果当 NavLinkto 属性是一级路由,但是Routepath匹配的是多级路由,组件是不会进行展示的。
这就是模糊匹配。

eg:

import React,  Component  from 'react'
import  Route, Switch  from 'react-router-dom'

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
import MyNavLink from './components/MyNavLink'
export default class App extends Component 
  render() 
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
                    /* 标签体中的内容会作为children属性传递给组件 */
                  <MyNavLink to="/home/a/b">

react路由

参考技术A 一、React路由: 实现单页应用的核心技术(单页应用 简称SPA)

路由原理参考资料:

二、React路由实现有两个包:

官网: https://reacttraining.com/react-router/
官方github: https://github.com/ReactTraining/react-router

中文路由文档: http://reacttraining.cn/web/example/basic

三、React-router-dom具体使用

Route:视图展示 区 相当于vue中的router-view
Link:要跳转的指令 相当于vue中的router-link

步骤:

1.引入所需的包:

2.用Link指令指令要跳转的路径

例如:

3.指定在哪个区域显示视图

例如:

4.如何指定高亮

例如:

可以通过activeClassName指定高亮类的样式,如果不指定activeClassName,可以直接使用active类名即可

5.路由传参

Reacr UI库 antd: 阿里
文档 https://ant.design/docs/react/introduce-cn

以上是关于React路由的主要内容,如果未能解决你的问题,请参考以下文章

如何通过链接和路由传递道具/状态 - react.js

配置 React.js 路由以运行 next.js

如何使用嵌套路由和私有路由组件在 react.js 中正确构建路由?

一个 Next.js 路由中的两个不同子域

REACT JS:TypeError:无法读取未定义的属性“参数”

react.js的两种路由方式:HashRouter