目录
单页应用程序 SPA:
- 整个应用只有一个完整的页面
- 点击页面中的链接不会刷新页面,只会做页面的局部更新
- 数据都需要通过ajax请求获取, 并在前端异步展现。
路由:
前端路由:
- 浏览器端路由,value是component,用于展示页面内容
- 注册路由:
<Route path="/test" component={Test}>
- 工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件
后端路由:
- 理解: value是function, 用来处理客户端提交的请求。
- 注册路由: router.get(path, function(req, res))
- 工作过程:当node接收到一个请求时, 根据请求路径和方法找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
一个路由就是一个映射关系(key:value)
key为路径, value可能是function或component
路由的基本使用
使用步骤
- 安装:
react-router-dom
- 导入路由的三个核心组件:Router/Route/Link
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
- 使用Router 组件包裹整个应用(重要)
<Router>
<div className="App">
//...
</div>
</Router>
- 使用Link 组件作为导航菜单(路由入口)
<Link to="/first">页面一</Link>
- 使用Route 组件配置路由规则和要展示的组件(路由出口)
const First = () => <p>页面一的页面内容</p>
<Router>
<div className="App">
<Link to="/first">页面一</Link>
<Route path="/first" component={First}></Route>
</div>
</Router>
常用组件说明
- Router组件:包裹整个应用,一个React应用只需要使用一次
- 两种常用Router:HashRouter和BrowserRouter
- HsahRouter:使用URL的哈希值实现(localhost:3000/#/first)
- (推荐)BrowserRouter:使用H5的history API实现(localhost:3000/first)
- Link组件:用于指定导航链接(a标签)
NavLink 标签是和 Link 标签作用相同的,但是它又比 Link 更加强大在之前案例中点击并没有高亮效果这时我们其实只需要对应设置active类名的样式即可因为当我们选中某个 NavLink 标签时,就会自动给当前标签添加active我们也可以通过activeClassName="zth"将激活时类名更改为zth.
- Router组件:指定路由展示组件相关信息
BrowserRouter和HashRouter的区别
底层原理不一样:
- BrowserRouter使用的是H5的````history``` API
- HashRouter使用的是URL的哈希值。
url表现形式不一样:
- BrowserRouter的路由中没有
#
符号 - HashRouter的路由中有
#
符号
刷新后对路由state参数的影响:
- BrowserRouter对state参数没有任何影响,因为state保存在history对象中,只要浏览器不清空缓存数据或关闭
- HashRouter对state参数有任何影响,state参数丢失。
路由的执行过程
- 点击Link组件(a标签),修改了浏览器地址栏中的url
- React路由监听到地址栏url的变化。
- React路由内部遍历所有Router组件,使用路由规则(path)与pathname进行匹配。
- 当路由规则(path)能够匹配地址栏中的pathname时,就展示该Router组件的内容
默认路由
- 默认路由:表示进入页面时就会匹配的路由
- 默认路由path为:/
- 默认情况下,React路由是模糊匹配模式
- 模糊匹配规则:只要pathname以path开头就会匹配成功
精确匹配
- 给Route组件添加exact属性,让其变为精确匹配模式
- 精确匹配:只有当path和pathname完全匹配时才会展示该路由
推荐:给默认路由添加exact属性
//此时,该组件只能匹配pathname="/"这一种情况
<Route exact path="/" component=... />
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>
)
}
}
重定向路由
我们有时会发现我们需要去点击一个按钮才去匹配组件但我们想要页面一加载就默认匹配到一个组件(页面一加载就会去匹配路由)这个时候我们就需要时候 Redirecrt 进行默认匹配实现此需求一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到 Redirect 指定的路由。
import { Redirect } from 'react-router-dom';
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
嵌套路由
将嵌套内容写在相应的组件里面,这个是在 Home 组件的 return jsx的 内容注册子路由时要写上父路由的path值路由的匹配是按照注册路由的顺序进行的,我们是在Home组件注册的,所以匹配时会先去找Home组件,因为时模糊匹配所以会匹配成功在 Home 组件里面去匹配相应的路由,从而找到 /home/news 进行匹配,因此找到 News 组件。
进行匹配渲染如果开启精确匹配(exact属性)的话,第一步的 /home/news 匹配 /home 就会卡住不动,就不会往Home组件里面去渲染嵌套的内容了
向路由组件传递参数
1.params参数
- 路由链接(携带参数):
<Link to='/demo/test/tom/18'}>详情</Link>
- 注册路由(声明接收):
<Route path="/demo/test/:name/:age" component={Test}/>
- 接收参数:
this.props.match.params
2.search参数
- 路由链接(携带参数):
<Link to='/demo/test?name=tom&age=18'}>详情</Link>
- 注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Test}/>
- 接收参数:
this.props.location.search
- 备注:获取到的search是urlencoded编码字符串,需要借助querystring解析
3.state参数
- 路由链接(携带参数):
<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
- 注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Test}/>
- 接收参数:
this.props.location.state
- 备注:刷新也可以保留住参数
编程式路由导航
我们可以采用绑定事件的方式实现路由的跳转,我们在按钮上绑定一个 onClick 事件,当事件触发时,我们执行一个回调 replaceShow
借助this.props.history对象上的API对操作路由跳转、前进、后退
- -this.props.history.push(path, state)
- -this.props.history.replace(path, state)
- -this.props.history.goBack()
- -this.props.history.goForward()
- -this.props.history.go()
withRouter
withRouter可以加工一般组件,让一般组件具备路由组件所特有的API,比如history 对象
withRouter的返回值是一个新组件
import React, { Component } from "react";
import { withRouter } from "react-router-dom";
class Header extends Component {
back = () => {
this.props.history.goBack();
};
forward = () => {
this.props.history.goForward();
};
go = () => {
this.props.history.go(-2);
};
render() {
console.log("Header组件收到的props是", this.props);
return (
<div className="page-header">
<h2>React Router Demo</h2>
<button onClick={this.back}>回退</button>
<button onClick={this.forward}>前进</button>
<button onClick={this.go}>go</button>
</div>
);
}
}
//在最后导出对象时,用 withRouter 函数进行包装
export default withRouter(Header);