Skip to main content

React应用-路由引入&案例

What is SPA

  • 单页 Web 应用( single page web application )
  • 整个==应用只有一个完整的页面==, 也就是一个HTML
  • 点击页面中的连接, ==不会刷新页面==, 只会做页面得到==局部更新==
  • 数据都需要通过ajax请求回去, 并在前端==异步展现=

What is React Route

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

  • key: IP或域名后的地址
  • value: 可能是function, 也可能是component

前端路由

路由的基本原理基于浏览器的windows的BOM对象的history属性, 但是BOM(内部是栈结构)的原生操作接口不友好, 因此, 借助第三方库history.js操作BOM属性, 从而实现前端路由

  • 如果==value内容对应的是一个组件Component==, 那么该路由为前端路由, 也叫浏览器路由, 用于页面展示内容
  • 注册方式: <Route path="./test" component={Test}>
  • 工作原理: 当==点击路由链接==后, 浏览器的path变为/test时, 当前路由组件就会变为Test组件

后端路由

相关案例: 与githubSearch案例相关的代理服务器实现

相关.zip压缩包地址:https://img.eksnotebook.com/images/202411101641169.zip

当前没有NAS, 所以就用这个凑乎一下

  • 如果==value内容对应的是一个function==, 那么该路由为后端路由, 用于处理客户端提交的请求
  • 注册方式: router.get(path, function(req, res))
  • 工作原理: 当node收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来请求处理, 返回响应数据

react-router-dom

tip
  • Router: 路由器

    • 比如小米路由器
  • Route: 路由

    • 比如小米路由器后面的插口
    • 需要使用Router管理Route
  • react-router, 有三个库, 分别对应不同场景

    • 给web专用( 当前的库, 更直接, 简单 )

    • 给native专用

    • 给两者通用

  1. react的一个插件库
  2. 专用来实现一个SPA应用
  3. 基于react的项目基本都会用到此库

主要API

// 内置组件
// 路由器
<BrowserRouter/> // 地址后面有'/'
<HashRouter/> // hash值( 锚点 ), 地址后面有'#' 后面内容不加到请求中,

<Redirect/>
<Link/> // 编写路由链接
<Route/> // 注册路由

<NavLink/> // Link的升级版, 可以高亮呦~~
<Switch/> // 包裹后, 仅匹配一次, 提高效率

// 其他
// history对象
// match对象
// withRouter函数

天禹老师课程小插曲

案例仓库地址

gitee仓库地址test/router

案例1:路由基本使用

  • 下载react-router-dom
  • 使用==本地bootstrap.css文件==

关键点

  1. 明确好界面中的导航区、展示区
  2. 导航区的a标签改为Link标签
    • <Link to="/xxxxx">Demo</Link>
  3. 展示区写Route标签进行路径的匹配
    • <Route path='/xxxx' component={Demo}/>
  4. <App>的最外侧包裹了一个<BrowserRouter><HashRouter>
    • 两个路由器无法通信

为什么NavLink默认有高亮?

NavLink 作为 Link 的升级版, 可以传入一个class属性:activeClassNameNavLink默认属性与bootscrap.css的高亮正好一致, 都是active 因此使用NavLink后, 就产生了高亮效果

那如果传入自定义的activeClassName??

  • 创建一个最高优先级的样式 !important

    ( bootscrap.css比较优先, 会产生被动替换 )

    •   .demo_css{
      background-color: reg(209, 137, 4) !important;
      color: white !important;
      }
  • 使用NavLink

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

封装样式NavLink为一般组件

==关于如何接标签体内容??== 其实, 标签体也是一种特殊的标签属性, 如下图内容

路由组件&一般组件区别

存放位置&调用不同
// 一般组件: src/Components
<Demo/>

// 路由组件: src/Pages
<Link to="/demo">Demo</Link>
<Route path="/demo" component={Demo}/>
收到的props不同
history:
/* */ go: ƒ go(n)
/* 后退 */ goBack: ƒ goBack()
/* 前进 */ goForward: ƒ goForward()
/* 添加路径 */ push: ƒ push(path, state)
/* 替换栈内容 */ replace: ƒ replace(path, state)
location:
/* */ pathname: "/about"
/* */ search: ""
/* */ state: undefined
match:
/* 模糊&精准匹配 */ isExact: true
/* */ params: {}
/* */ path: "/about"
/* */ url: "/about"

Switch的使用

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

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

解决样式丢失问题

当使用二级路径后, 使用组件过后, 刷新界面 会导致相对路径下的bootstrap样式丢失

当不加%PUBLIC_URL%, 更换路由多级路径后, 再次刷新时, 会导致请求文件的相对路径改变 导致文件丢失, 默认加载index.html

解决方案

  • 使用路径/css/bootstrap.css
  • 使用路由器<HashRouter/>
    • 原因是该路由器#号后方内容不带入请求
  • ==仅适用于脚手架==

路由的模糊与严格匹配

  • ==默认使用的是模糊匹配==
    • 【输入的路径】必须包含要【匹配的路径】,==且顺序要一致==
  • 开启严格匹配:
    • <Route exact={true} path="/about" component={About}/>
    • <Route exact path="/about" component={About}/>
    • 严格匹配不要随便开启,需要再开,==有些时候开启会导致无法继续匹配二级路由==

重定向Redirect

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

案例2:路由嵌套使用

嵌套路由使用说明

  1. 路由的路径匹配, 都是从注册顺序比较的
  2. 注册子路由时要写上父路由的path值

案例3:向路由组件传递参数数据

params参数

路由链接(携带参数)
<Link to='/demo/test/tom/18'}>详情</Link>

注册路由(声明接收)
<Route path="/demo/test/:name/:age" component={Test}/>

接收参数:
this.props.match.params

search参数

路由链接(携带参数)
<Link to='/demo/test?name=tom&age=18'}>详情</Link>

注册路由(无需声明,正常注册即可)
<Route path="/demo/test" component={Test}/>

接收参数:
this.props.location.search

备注:
获取到的search是urlencoded编码字符串,需要借助querystring解析
其中 querystring 已更新为 querystring-es3

state参数

路由链接(携带参数)
<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>

注册路由(无需声明,正常注册即可)
<Route path="/demo/test" component={Test}/>

接收参数:
this.props.location.state
备注:刷新也可以保留住参数

案例4:多种路由跳转方式

借助this.prosp.history对象上的API对操作路由跳转、前进、后退
- this.prosp.history.push()
- this.prosp.history.replace()
- this.prosp.history.goBack()
- this.prosp.history.goForward()
- this.prosp.history.go()

一般组件方法: withRouter

注意上述路由跳转方式,

只能用于路由组件才有 .history 属性

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

返回值为一个新组件

使用方式
// 将一般组件暴露方式修改一下
class Header extends Component {}
export default withRouter(Header)

BrowserRouter与HashRouter的区别

1.底层原理不一样:
BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
HashRouter使用的是URL的哈希值。

2.path表现形式不一样
BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
HashRouter的路径包含#,例如:localhost:3000/#/demo/test

3.刷新后对路由state参数的影响
(1).BrowserRouter没有任何影响,因为state保存在history对象中。
(2).HashRouter刷新后会导致路由state参数的丢失!!!

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