React路由

React路由

一 对SPA应用的理解

需要理解的概念有:

  • 什么是SPA
  • SPA和MPA的区别
  • 实现一个SPA
  • 如何给SPA做SEO
  • SPA与MPA网站演示

1.什么是SPA

  1. 单页web应用(single-page application),翻译过来就是单页应用。

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

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

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

React路由_第1张图片

2.SPA和MPA的区别

上面大家已经对单页面有所了解了,下面来讲讲多页应用。

MPA(MultiPage-page application),翻译过来就是多页应用。

在MPA中,每个页面都是一个主页面,都是独立的。

当我们在访问另一个页面的时候,都需要重新加载html、css、js文件,公共文件则根据需求按需加载。

如下图

React路由_第2张图片

单页应用与多页应用的区别

单页面应用(SPA) 多页面应用(MPA)
组成 一个主页面和多个页面片段 多个主页面
刷新方式 局部刷新 整页刷新
url模式 哈希模式 历史模式
SEO搜索引擎优化 难实现,可使用SSR方式改善 容易实现
数据传递 容易 通过url、cookie、localStorage等传递
页面切换 速度快,用户体验良好 切换加载资源,速度慢,用户体验差
维护成本 相对容易 相对复杂

单页应用优势与不足

优点:

  • 具有桌面应用的即时性、网站的可移植性和可访问性
  • 用户体验好、快,内容的改变不需要重新加载整个页面
  • 良好的前后端分离,分工更明确

不足:

  • 不利于搜索引擎的抓取
  • 首次渲染速度相对较慢

3.实现一个SPA

原理

  1. 监听地址栏中hash变化驱动界面变化
  2. pushsate记录浏览器的历史,驱动界面发送变化

React路由_第3张图片

实现

hash 模式

核心通过监听url中的hash来进行路由跳转

// 定义 Router
class Router {
    constructor () {
        this.routes = {}; // 存放路由path及callback
        this.currentUrl = '';
        
        // 监听路由change调用相对应的路由回调
        window.addEventListener('load', this.refresh, false);
        window.addEventListener('hashchange', this.refresh, false);
    }
    
    route(path, callback){
        this.routes[path] = callback;
    }
    
    push(path) {
        this.routes[path] && this.routes[path]()
    }
}
 
// 使用 router
window.miniRouter = new Router();
miniRouter.route('/', () => console.log('page1'))
miniRouter.route('/page2', () => console.log('page2'))
 
miniRouter.push('/') // page1

history模式
history 模式核心借用 HTML5 history api,api 提供了丰富的 router 相关属性

先了解一个几个相关的api history.pushState 浏览器历史纪录添加记录
history.replaceState修改浏览器历史纪录中当前纪录
history.popState 当 history 发生变化时触发

// 定义 Router
class Router {
    constructor () {
        this.routes = {};
        this.listerPopState()
    }
    
    init(path) {
        history.replaceState({path: path}, null, path);
        this.routes[path] && this.routes[path]();
    }
    
    route(path, callback){
        this.routes[path] = callback;
    }
    
    push(path) {
        history.pushState({path: path}, null, path);
        this.routes[path] && this.routes[path]();
    }
    
    listerPopState () {
        window.addEventListener('popstate' , e => {
            const path = e.state && e.state.path;
            this.routers[path] && this.routers[path]()
        })
    }
}
 
// 使用 Router
 
window.miniRouter = new Router();
miniRouter.route('/', ()=> console.log('page1'))
miniRouter.route('/page2', ()=> console.log('page2'))
 
// 跳转
miniRouter.push('/page2')

4.如何给SPA做SEO

面给出基于Vue的SPA如何实现SEO的三种方式:

  • SSR服务端渲染

将组件或页面通过服务器生成html,再返回给浏览器,如nuxt.js

  • 静态化

目前主流的静态化主要有两种:

(1)一种是通过程序将动态页面抓取并保存为静态页面,这样的页面的实际存在于服务器的硬盘中

(2)另外一种是通过WEB服务器的 URL Rewrite的方式,它的原理是通过web服务器内部模块按一定规则将外部的URL请求转化为内部的文件地址,一句话来说就是把外部请求的静态地址转化为实际的动态页面地址,而静态页面实际是不存在的。这两种方法都达到了实现URL静态化的效果

  • 使用Phantomjs针对爬虫处理

原理是通过Nginx配置,判断访问来源是否为爬虫,如果是则搜索引擎的爬虫请求会转发到一个node server,再通过PhantomJS来解析完整的HTML,返回给爬虫。

React路由_第4张图片

5.SPA与MPA网站演示

SPA:www.qiniu.com、阿里云平台、腾讯云平台等

MPA:www.163.com

二 对路由的理解

需要理解的概念有:

  • 路由概念的核心词汇:静态路由表,分配地址,统一入口,寻址以及过滤

  • 什么是路由:

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

    2 key为路径,value可能是function或component

  • 路由的分类

    1 后端路由:

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

    ​ ② 注册路由:router.get(path,function(req,res))

    ​ ③ 工作过程:当node接受到一个请求时,根据请求路径找到匹配的路由,条用路由中的函数来处理请求,返回响应数据

    2 前端路由:

    ​ ① 浏览器路由:value是component,用于展示页面内容

    ​ ② 注册路由:

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

React路由_第5张图片

对于路由的功能实现原理现在可以大致做个剖析,它其实是提供了一种方式给各个场景之间进行切换操作并且管理其导航历史,每个场景都像一图层,可以推送至其它场景的最后面,当然,如果你将它删除就无法实现该操作了。我们尝试以一种更容易理解的方式进行解释,就是将路由理解成翻书操作,所有的页面就是我们配置的路由模块,可以将书本翻至某一页,也就是其中某一模块,也可以翻到另一页,另一个模块内容,当然,如果需要,还是可以翻回到刚才的那一页的,前提是你不能把那页纸给撕了。

三 前端路由原理

需要理解的概念有:

  • HTML+CSS能否实现SPA项目
  • 前端路由实现原理的核心模块是什么
  • 前端路由的跳转模式主要有哪些
  • 锚点与历史跳转的差异

利用HTML+CSS实现的SPA:http://qn.chinavanes.com/anchor-router.zip

前端路由实现原理的核心模块:https://github.com/ReactTraining/history

  1. history库
  • 管理浏览器会话历史(history)的工具库
  • 包装的是原生BOM中window.history和window.location.hash
  1. history API
  • History.createBrowserHistory(): 得到封装window.history的管理对象
  • History.createHashHistory(): 得到封装window.location.hash的管理对象
  • history.push(): 添加一个新的历史记录
  • history.replace(): 用一个新的历史记录替换当前的记录
  • history.goBack(): 回退到上一个历史记录
  • history.goForword(): 前进到下一个历史记录
  • history.listen(function(location){}): 监视历史记录的变化

前端路由实现原理核心模块的应用:http://qn.chinavanes.com/history-router.zip

四 路由的基本使用

需要理解的概念有:

  • react-router各个模块包的功能与差异
  • React-router的核心API有哪些

1.react-router各个模块包的功能与差异

react-router的github地址:https://github.com/ReactTraining/react-router
react-router的官网项目地址:https://reactrouter.com/

react-router的理解:

  • react的一个插件库
  • 专门用来实现一个SPA应用
  • 基于react的项目基本都会用到此库

1、React-router与React-router-dom的功能对比
React-router:实现了路由的核心功能
React-router-dom:基于React-router,加入了一些在浏览器运行下的一些功能,
例如:Link组件会渲染一个a标签
BrowserRouter使用 HTML5 提供的 history API可以保证你的 UI 界面和 URL 保持同步
HashRouter使用 URL 的 hash 部分保证你的 UI 界面和 URL 保持同步

2、React-router与React-router-dom的API对比
React-router:提供了router的核心api。如Router、Route、Switch等,但没有提供有关dom操作进行路由跳转的API
React-router-dom:提供了BrowserRouter、Route、Link等API,可以通过dom操作触发事件控制路由

2.React-router的核心API有哪些

BrowserRouter 浏览器模式路由,PC端
HashRouter Hash值模式路由,PC端
Link 普通链接
NavLink 导航链接
Prompt 提示
MemoryRouter 内存模式路由,ReactNative移动端
Redirect 重定向
Route 单个路由对象
Router 整体路由对象
StaticRouter 静态路由,SSR服务器端渲染使用
Switch 选择路由
generatePath 生成路由地址
history 历史
location 地址
match 匹配
matchPath 匹配路径
withRouter 接收路由的HOC组件

3.创建基本路由切换

src/components/Home/index.js

import React, { Component } from 'react';

export default class Home extends Component {
	render() {
		return 
我是Home组件
; } }

src/components/About/index.js

import React, { Component } from 'react';

export default class About extends Component {
	render() {
		return 
我是About组件
; } }

3.1注册路由,设置静态路由表,并且分配地址

src/App.js 安装react-router-dom

目前报错:Error: Invariant failed: You should not use outside a

import React, { Component } from 'react';
import { Route } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';

class App extends Component {
	render() {
		return (
			

React Router Demo

{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

3.2利用BrowserRoute进行静态路由表的包含

Route是什么?Route是路由

BrowserRouter与Route的关系是什么?

Router代表的是一整个路由对象,它是数组

Route是整个路由对象中的其中一个而已,是单一的路由模块对象

import React, { Component } from 'react';
import { Route, BrowserRouter } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';

class App extends Component {
	render() {
		return (
			

React Router Demo

{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

3.3利用传统的A链接进行路由切换遇到问题,页面整体还是刷新

原生html中,靠跳转到不同的页面

1.A链接可以配合HashRouter进行路由的跳转以及SPA的实现,但是无法配合

BrowserRouter进行操作处理,在链接点击以后,整个页面将会进行刷新的操作

2.利用A链接不容易实现高亮的显示操作

import React, { Component } from 'react';
import { Route, BrowserRouter } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';

class App extends Component {
	render() {
		return (
			

React Router Demo

{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

3.4 利用Link进行路由跳转的尝试

在react中靠路由链接实现切换组件

目前报错:Error: Invariant failed: You should not use outside a

import React, { Component } from 'react';
import { Route, BrowserRouter, Link } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';

class App extends Component {
	render() {
		return (
			

React Router Demo

{/* 原生HTML中,靠标签跳转不同的页面 */} {/* About Home */} {/* 在React中,则需要利用路由链接切换实现--编写路由链接 */} About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

3.5确认有几个路由对象?

import React, { Component } from 'react';
import { Route, BrowserRouter, Link } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';

class App extends Component {
	render() {
		return (
			

React Router Demo

{/* 原生HTML中,靠标签跳转不同的页面 */} {/* About Home */} {/* 在React中,则需要利用路由链接切换实现--编写路由链接 */} About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

3.6 有且只有一个路由对象,统一入口

将BrowserRotuer迁移至最顶层,也就是入口文件中

index.js

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

App.js

import React, { Component } from 'react';
import { Link, Route } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';

class App extends Component {
	render() {
		return (
			

React Router Demo

{/* 原生HTML中,靠标签跳转不同的页面 */} {/* About Home */} {/* 在React中,则需要利用路由链接切换实现--编写路由链接 */} About Home
{/* 注册路由*/}
); } } export default App;

五 路由组件与一般组件

需要理解的概念有:

1 普通组件:

​ 1) 存放路径:components

​ 2)属性内容:它是没有路由相关的属性对象的

​ 3)操作方式:手动调用

​ 4) 写法不同:

2 路由组件:

​ 1)存放路径:pages

​ 2)属性内容:有路由相关的属性对象的,包括history(go、goBack、goForward、 location、push、replace等),location、match等内容

​ 3) 操作方式:切换

​ 4) 写法不同:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AfmtzAjv-1624175919878)(C:\Users\angi\AppData\Roaming\Typora\typora-user-images\image-20210609204052191.png)]

1.将components目录名称修改成pages,因为Home与About是路由组件

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';

class App extends Component {
	render() {
		return (
			

React Router Demo

{/* 原生HTML中,靠标签跳转不同的页面 */} {/* About Home */} {/* 在React中,则需要利用路由链接切换实现--编写路由链接 */} About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

2.将头部功能拆分成一般组件,存储于src/components/Header目录中

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link } from 'react-router-dom';
import Home from './pages/Home'; // 路由组件
import About from './pages/About'; // 路由组件
import Header from './components/Header'; // 一般组件

class App extends Component {
	render() {
		return (
			
About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

src/components/Header/index.js

import React, { Component } from 'react';

export default class Header extends Component {
	render() {
		console.log('一般组件属性接收:', this.props);
		return (
			

React Router Demo

); } }

3.区别路由组件与一般组件的属性接收内容

import React, { Component } from 'react';

export default class Home extends Component {
	render() {
		console.log('路由组件属性接收:', this.props);
		return 
我是Home组件
; } }
1.使用方式不同:
    (1)一般组件:靠程序员亲自写组件标签去渲染,例如:
    (2)路由组件:靠路由器进行路径的匹配,从而渲染的

2.存放文件夹不同:
    (1)一般组件:components
    (2)路由组件:pages

3.收到的props不同
    (1)一般组件:程序员写组件标签时传入了什么,那么props中的内容就是什么,
    	例如:
    (2)路由组件:会收到固定的几个props,如下:
        history:
            go: ƒ go(n)
            goBack: ƒ goBack()
            goForward: ƒ goForward()
            location: {pathname: "/about", search: "", 
            hash: "", state: null, key: "1f5ocf"}
            push: ƒ push(path, state) //控制路由跳转
            replace: ƒ replace(path, state) //控制路由跳转

        location:
            pathname: "/about"
            search: "" //专门用于接收路由search参数
            state: null // 专门用于接收路由state参数

        match:
            params: {}  //专门用于接收路由params参数
            path: "/about"
            url: "/about"

六 NavLink的使用

需要理解的概念有:

  • 如何实现链接的高亮显示
  • Link与NavLink的差异

1 A标签:可以配合HashRouter不可以配合BrowserRouter,而且不容易实现高亮,如果想要实现高亮,就必须使用真实DOM选择操作处理

2 Link标签:可以配合HashRouter以及BrowserRouter进行路由的切换,但是无法实现高亮显示

3 NavLink标签:是一种特殊的Link,可以配合HashRouter以及BrowserRouter进行路由切换,Link所有的功能它都有,并且增加了高亮等操作内容

1.Link中没有特定属性可以设置高亮

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Header from './components/Header';

class App extends Component {
	render() {
		return (
			
{/* 原生HTML中,靠标签跳转不同的页面 */} {/* About Home */} {/* 在React中,则需要利用路由链接切换实现--编写路由链接 */} About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

2.利用NavLink替换Link,并设置activeClassName高亮属性

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Header from './components/Header';

class App extends Component {
	render() {
		return (
			
About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

3.自定义active样式内容的设置

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Header from './components/Header';

class App extends Component {
	render() {
		return (
			
About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

public/index.html

权重:!important;


<html lang="en">

<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>React Apptitle>
  <link rel="stylesheet" href="./css/bootstrap.css">
  <style>
    .atguigu {
      background-color: orange !important;
      color: white !important;
    }
  style>
head>

<body>
  <div id="root">div>
body>

html>

七 对NavLink进行二次封装

需要理解的概念有:

  • 自定义组件的封装与属性的传递

1 保留静态代码

2 提取动态参数属性

  • naveLink可以实现路由链接的高亮,通过activeClassName指定样式名
  • 标签体内容是一个特殊的标签属性
  • 通过this.props.children可以获取标签体内容

1.常规参数的传递与不定参数的传递

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Header from './components/Header';
import MyNavLink from './components/MyNavLink';

class App extends Component {
	render() {
		return (
			
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

src/components/MyNavLink/index.js

封装NavLink

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

export default class MyNavLink extends Component {
	render() {
		const { to, title } = this.props;
		return (
{title}
		);
	}
}

src/components/MyNavLink/index.js

不定参数的传递

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

export default class MyNavLink extends Component {
	render() {
		const { title } = this.props; 
		return (
{title}
		);
	}
}

2.标签体内容属性的传递

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Header from './components/Header';
import MyNavLink from './components/MyNavLink';

class App extends Component {
	render() {
		return (
			
About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

src/components/MyNavLink/index.js

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

export default class MyNavLink extends Component {
	render() {
		const { to, children } = this.props;
		return (
{children}
		);
	}
}

八 Switch的使用

需要理解的概念有:

  • Switch选择路由的作用

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

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

1.没有Switch的应用

src/pages/Test/index.js

import React, { Component } from 'react';

export default class Test extends Component {
	render() {
		return 
Test
; } }

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Test from './pages/Test';
import Header from './components/Header';
import MyNavLink from './components/MyNavLink';

class App extends Component {
	render() {
		return (
			
{/* 原生HTML中,靠标签跳转不同的页面 */} {/* About Home */} {/* 在React中,则需要利用路由链接切换实现--编写路由链接 */} About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

2.使用Switch的选择路由,单一匹配

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink, Switch } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Test from './pages/Test';
import Header from './components/Header';
import MyNavLink from './components/MyNavLink';

class App extends Component {
	render() {
		return (
			
About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

九 解决样式丢失问题

需要理解的概念有:

  • public中样式引入的路径问题

1.修改链接与路由路径,并重新刷新整个页面,将会产生样式失效问题

查看bootstrap.css样式的内容,会发现虽然没报404,但样式本质并没有引入正确,返回的是public/index.html,其本质是因为react脚手架项目,如果输入路径找不到都将返回public/index.html的代码内容。

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink, Switch } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Header from './components/Header';
import MyNavLink from './components/MyNavLink';

class App extends Component {
	render() {
		return (
			
{/* 在React中,则需要利用路由链接切换实现--编写路由链接 */} About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

React路由_第6张图片

2.解决样式丢失的三种方式

2.1利用%PUBLIC_URL%前缀可以确认路径


<html lang="en">

<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>React Apptitle>
  
  <link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">
  <style>
    .atguigu {
      background-color: orange !important;
      color: white !important;
    }
  style>
head>

<body>
  <div id="root">div>
body>

html>

2.2直接确认是根目录开始查找


<html lang="en">

<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>React Apptitle>
  
  <link rel="stylesheet" href="/css/bootstrap.css">
  <style>
    .atguigu {
      background-color: orange !important;
      color: white !important;
    }
  style>
head>

<body>
  <div id="root">div>
body>

html>

2.3利用HashRouter代替BrowserRouter,则不需要修改index.html中的css路径

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { HashRouter } from 'react-router-dom';
ReactDOM.render(
	
		
	,
	document.getElementById('root')
);

十 严格匹配与模糊匹配

需要理解的概念有:

  • 模糊匹配以及其规则
  • 精确匹配的处理

匹配原则:

​ 1.默认都是模糊匹配

​ 2.可以利用exact属性进行精确匹配

​ 1)路由的精确匹配

​ 2)路由链接的精确匹配

1.路径的模糊匹配

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink, Switch } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Header from './components/Header';
import MyNavLink from './components/MyNavLink';

class App extends Component {
	render() {
		return (
			
About {/* 以开头匹配,所以下面写法匹配的到 */} Home {/* 以开头匹配,所以下面写法匹配不到 */} Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

2.路径的精确匹配

利用exact进行精确匹配处理

1.默认使用的是模糊匹配 2.开启严格匹配: 3.一定要谨慎开启严格匹配模式,因为一旦开启严格匹配会造成该路由的所有子路由全部失效

src/App.js

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink, Switch } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Header from './components/Header';
import MyNavLink from './components/MyNavLink';

class App extends Component {
	render() {
		return (
			
About Home Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */}
); } } export default App;

十一 Redirect的使用

需要理解的概念有:

  • Redirect重定向
  • 不匹配的处理
import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink, Switch, Redirect } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Header from './components/Header';
import MyNavLink from './components/MyNavLink';

class App extends Component {
	render() {
		return (
			
About Home Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */} {/* 路径都不匹配的情况下,执行以下重定向,一般写在所有路由最下方 */} {/* */}
); } } export default App;

十二 嵌套路由

需要理解的概念有:

  • 注册二级路由时,必须包含一级路由的路径
  • 嵌套路由时exact的合理考虑

嵌套路由页面地址:http://qn.chinavanes.com/route_page2.zip

React路由_第7张图片

1.嵌套路由的基本结构(无法显示子路由页面组件)

src/pages/Home/Message/index.js

import React, { Component } from 'react';

export default class Message extends Component {
	render() {
		return (
			
		);
	}
}

src/pages/Home/Message/index.js

import React, { Component } from 'react';

export default class News extends Component {
	render() {
		return (
			
  • news001
  • news002
  • news003
); } }

src/pages/Home/index.js

注册二级路由时,必须包含一级路由的路径

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink, Switch, Redirect } from 'react-router-dom';
import MyNavLink from '../../components/MyNavLink';
import Message from './Message';
import News from './News';

export default class Home extends Component {
	render() {
		return (
			

Home组件内容

  • News
  • Message
{/* 注册路由 */}
); } }

2.合理考虑exact的精确匹配

src/App.js

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

class App extends Component {
	render() {
		return (
			
About Home
{/* 注册路由:设置静态路由表,并且分配路由地址 */} {/* 路径都不匹配的情况下,执行以下重定向 */}
); } } export default App;

src/pages/Home/index.js

重定向的应用

import React, { Component } from 'react';
import { Route, BrowserRouter, Link, NavLink, Switch, Redirect } from 'react-router-dom';
import MyNavLink from '../../components/MyNavLink';
import Message from './Message';
import News from './News';

export default class Home extends Component {
	render() {
		return (
			

Home组件内容

  • News
  • Message
{/* 注册路由 */}
); } }

十三 向路由组件传递params参数

需要理解的概念有:

  • 参见请求的参数类型:params、query、body的data
  • 有关参数的理解:设参、传参、接参、用参
  • react中路由params参数的位置:设参在路由、传参在地址、接参在组件、用参也在组件

React路由_第8张图片

src/pages/Home/Message/index.js

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

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}>
								{/*传参在地址*/}
								<Link 
								to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>
								{msgObj.title}
								</Link>
							</li>
						);
					})}
				</ul>
				<hr />
				{/*设参在路由*/}
				<Route path='/home/message/detail/:id/:title' 
				component={Detail} />
			</div>
		);
	}
}

src/pages/Home/Message/Detail/index.js

import React, { Component } from 'react';

const DetailData = [
	{ id: '01', content: '你好,中国' },
	{ id: '02', content: '你好,尚硅谷' },
	{ id: '03', content: '你好,自己' },
];

export default class Detail extends Component {
	render() {
		// 查看参数内容
		console.log(this.props);
		// 接参在组件
		const { id, title } = this.props.match.params;
		const findResult = DetailData.find((detailObj) => {
			return detailObj.id === id;
		});
		return (
			
    {/*用参在组件*/}
  • id:{id}
  • title:{title}
  • content:{findResult.content}
); } }

1.params参数(在路径中拼接进去,即:to只能写字符串)
通过路由链接携带参数:详情
注册路由(一定要声明接收!!!):
接收参数:this.props.match.params

十四 向路由组件传递search参数

需要理解的概念有:

  • react中路由query参数的位置:设参传参在地址、接参用参在组件

src/pages/Home/Message/index.js

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

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 (
			
    {messageArr.map((msgObj) => { return (
  • {/*传参在地址*/} {/*{msgObj.title}*/} {msgObj.title} {msgObj.title}
  • ); })}

{/*设参在路由*/} {/* */}
); } }

src/pages/Home/Message/Detail/index.js

import React, { Component } from 'react';
import qs from 'querystring';

const DetailData = [
	{ id: '01', content: '你好,中国' },
	{ id: '02', content: '你好,尚硅谷' },
	{ id: '03', content: '你好,自己' },
];

export default class Detail extends Component {
	render() {
		// 查看参数内容
		console.log(this.props);
		// 接参在组件
		// const { id, title } = this.props.match.params;
		const { search } = this.props.location;
		const { id, title } = qs.parse(search.slice(1));

		const findResult = DetailData.find((detailObj) => {
			return detailObj.id === id;
		});
		return (
			
    {/*用参在组件*/}
  • id:{id}
  • title:{title}
  • content:{findResult.content}
); } }

2.search参数(可以路径中拼接,或把to写成对象,靠search属性传递)
通过路由链接携带参数:详情
注册路由(无需声明接收):
接收参数:this.props.location.search
备注:需要借助querystring进行解析

十五 向路由组件传递state参数

需要理解的概念有:

  • state数据在什么时候无法获取
  • state参数的传递与获取

src/pages/Home/Message/index.js

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

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 (
			
    {messageArr.map((msgObj) => { return (
  • {/*传参在地址*/} {/*{msgObj.title} {msgObj.title} */} {msgObj.title}
  • ); })}

{/*设参在路由*/} {/* */}
); } }

src/pages/Home/Message/Detail/index.js

import React, { Component } from 'react';
import qs from 'querystring';

const DetailData = [
	{ id: '01', content: '你好,中国' },
	{ id: '02', content: '你好,尚硅谷' },
	{ id: '03', content: '你好,自己' },
];

export default class Detail extends Component {
	render() {
		// 查看参数内容
		console.log(this.props);
		// 接参在组件
		// const { id, title } = this.props.match.params;
		// const { search } = this.props.location;
		// const { id, title } = qs.parse(search.slice(1));

		const { id, title } = this.props.location.state || {};

		const findResult =
			DetailData.find((detailObj) => {
				return detailObj.id === id;
			}) || {};

		return (
			
    {/*用参在组件*/}
  • id:{id}
  • title:{title}
  • content:{findResult.content}
); } }
3.state参数(只能把to写成对象,靠state属性传递)
路由链接(携带参数):详情
注册路由(无需声明接收):
接收参数:this.props.location.state

十六 总结路由参数

需要理解的概念有:

  • 参数的类型有哪些,如何设置、传递、接收与使用
1.params参数(在路径中拼接进去,即:to只能写字符串)  
通过路由链接携带参数:详情
注册路由(一定要声明接收!!!):   
接收参数:this.props.match.params

2.search参数(可以路径中拼接,或把to写成对象,靠search属性传递)  
通过路由链接携带参数:详情
注册路由(无需声明接收):
接收参数:this.props.location.search  
备注:需要借助querystring进行解析

3.state参数(只能把to写成对象,靠state属性传递)
路由链接(携带参数):详情
注册路由(无需声明接收):
接收参数:this.props.location.state

十七 push与repalce

需要理解的概念有:

  • push与replace的区别

src/pages/Home/Message/index.js

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

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 (
			
    {messageArr.map((msgObj) => { return (
  • {/*传参在地址*/} {/*{msgObj.title} {msgObj.title} */} {msgObj.title}
  • ); })}

{/*设参在路由*/} {/* */}
); } }

十八 编程式路由导航

需要理解的概念有:

  • push与replace的差异
  • goForward、goBack、go的应用
  • 设参、传参、接参、用参的步骤与路由的关系

src/pages/Home/Message/index.js

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

export default class Message extends Component {
	state = {
		messageArr: [
			{ id: '01', title: '消息1' },
			{ id: '02', title: '消息2' },
			{ id: '03', title: '消息3' },
		],
	};

	pushShow = (id, title) => {
		// push跳转+params传参
		// this.props.history.push(`/home/message/detail/${id}/${title}`);
		// push跳转+search传参
		// this.props.history.push(`/home/message/detail?id=${id}&title=${title}`);
		// push跳转+state传参
		this.props.history.push('/home/message/detail', { id, title });
	};

	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 });
	};

	forward = () => {
		this.props.history.goForward();
	};

	back = () => {
		this.props.history.goBack();
	};

	go = () => {
		this.props.history.go(-2);
	};

	render() {
		const { messageArr } = this.state;
		return (
			
    {messageArr.map((msgObj) => { return (
  • {/*传参在地址*/} {/*{msgObj.title} {msgObj.title} */} {msgObj.title}
  • ); })}

{/*设参在路由*/} {/* */}
); } }

十九 withRouter的使用

需要理解的概念有:

  • 一般组件与路由组件的差异与区别
  • withRouter是一个HOC,也就是高阶段组件
  • 什么是HOC高阶组件

src/components/Header/index.js

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

class Header extends Component {
	back = () => {
		// 该组件属于一般组件,props属性中不带有路由相关内容
		console.log(this.props);
		this.props.history.goBack();
	};
	render() {
		console.log('一般组件属性接收:', this.props);
		return (
			<div className='page-header'>
				<h2>React Router Demo</h2>
				<button className='btn btn-primary' onClick={this.back}>
					返回
				</button>
			</div>
		);
	}
}

// 将普通组件转化成带路由功能的组件
export default withRouter(Header);

二十 Prompt的使用

需要理解的概念有:

  • Prompt阻止页面离开
import React, { Component } from 'react';
import { Prompt } from 'react-router-dom';
export default class News extends Component {
	state = { isBlocking: false };
	blocking = () => {
		this.setState({ isBlocking: !this.state.isBlocking });
	};
	render() {
		const { isBlocking } = this.state;
		return (
			
    {isBlocking.toString()} `你确认想要去 ${location.pathname}`} />
  • news001
  • news002
  • news003
); } }

二十 BrowserRouter与HashRouter(5)

需要理解的概念有:

  • 底层原理不一样:
    • BrowserRouter使用的是H5的History API,不兼容IE9及以下版本
    • HashRouter使用的是URL的哈希值
  • url表现形式不一样
    • BrowserRouter的路径中没有#,例如:http://localhost:3000/demo/test
    • HashRouter的路径包含#,例如:http://localhost:3000/#/demo/test
  • 刷新后对路由state参数的影响
    • BrowserRouter没有任何影响,因为state保存在history对象中

    • HashRouter刷新后会导致由state参数的丢失
      >
      push查看

      className=‘btn btn-primary’
      onClick={() => this.replaceShow(msgObj.id, msgObj.title)}
      >
      replace查看


    • );
      })}



    {/设参在路由/}
    {/*


    */}
    		
    		
    		
    	
);

}
}


# 十九 withRouter的使用

需要理解的概念有:

- 一般组件与路由组件的差异与区别
- withRouter是一个HOC,也就是高阶段组件
- 什么是HOC高阶组件

src/components/Header/index.js

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

class Header extends Component {
	back = () => {
		// 该组件属于一般组件,props属性中不带有路由相关内容
		console.log(this.props);
		this.props.history.goBack();
	};
	render() {
		console.log('一般组件属性接收:', this.props);
		return (
			

React Router Demo

); } } // 将普通组件转化成带路由功能的组件 export default withRouter(Header);

二十 Prompt的使用

需要理解的概念有:

  • Prompt阻止页面离开
import React, { Component } from 'react';
import { Prompt } from 'react-router-dom';
export default class News extends Component {
	state = { isBlocking: false };
	blocking = () => {
		this.setState({ isBlocking: !this.state.isBlocking });
	};
	render() {
		const { isBlocking } = this.state;
		return (
			
    {isBlocking.toString()} `你确认想要去 ${location.pathname}`} />
  • news001
  • news002
  • news003
); } }

二十 BrowserRouter与HashRouter(5)

需要理解的概念有:

  • 底层原理不一样:
    • BrowserRouter使用的是H5的History API,不兼容IE9及以下版本
    • HashRouter使用的是URL的哈希值
  • url表现形式不一样
    • BrowserRouter的路径中没有#,例如:http://localhost:3000/demo/test
    • HashRouter的路径包含#,例如:http://localhost:3000/#/demo/test
  • 刷新后对路由state参数的影响
    • BrowserRouter没有任何影响,因为state保存在history对象中
    • HashRouter刷新后会导致由state参数的丢失
  • 备注:HashRouter可以用于解决一些路径错误相关的问题

你可能感兴趣的:(react)