1、相关理解
Ⅰ-SPA的理解
单页Web应用(single page web application,SPA)。
整个应用只有一个完整的页面。
点击页面中的链接不会刷新页面,只会做页面的局部更新。
数据都需要通过ajax请求获取, 并在前端异步展现。
Ⅱ-路由的理解
根据不同的路径,显示不同的组件(内容)
- 前端路由功能:让用户从一个视图(页面)导航到另一个视图(页面)
- 前端路由是一套映射规则,在React中,是URL路径与组件的对应关系
Ⅲ-react-router-dom的理解
①相关概念
react的一个插件库。
专门用来实现一个SPA应用。
基于react的项目基本都会用到此库。
②相关api
1、内置组件
<BrowserRouter>
<HashRouter>
<Route>
<Redirect>
<Link>
<NavLink>
<Switch>
2、其他
history对象
match对象
withRouter函数
2、路由的基本使用
1.
<App>
的最外侧包裹了一个<BrowserRouter>或<HashRouter>
App.js
使用H5的history API实现(localhost3000/first)
使用URL的哈希值实现 (localhost:3000/#/first)import {BrowserRouter } from "react-router-dom" //按需导入 ReactDOM.render( <BrowserRouter> <App/> </BrowserRouter>, document.getElementById('root') )
2.展示区写Route标签进行路径的匹配
import { Route, Switch, Redirect } from "react-router-dom"; import Home from "../pages/Home/Home" import User from "../pages/User/User" import Animate from "../pages/Animate/Animate" export default function MyRouter() { return ( <Switch> {/* 主页路由要加exact精确匹配,因为每一个路径都有/,不精确下,都会匹配主页 */} <Route exact path="/home" component={Home} /> {/* 正常路由建议加exact, 动态路由因为路径不固定, 不能加exact */} <Route exact path="/user" component={User} /> {/* Redirect 用于路由重定向 */} {/* <Redirect path="/" to="/home"/> */} <Route exact path="/Animate" component={Animate} /> </Switch> ) }
3.明确好界面中的导航区、展示区
import {Link} from "react-router-dom" //按需导入 <Link to="/xxxxx">Demo</Link> <RouterView></RouterView>
3、路由组件与一般组件
1.写法不同:
一般组件:
<Demo/>
路由组件:
<Route path="/demo" component={Demo}/>
2.存放位置不同:
一般组件:components
路由组件:pages
3. 接收到的props不同:一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到三个固定的属性
//路由属性打印结果展示 history: go: ƒ go(n) goBack: ƒ goBack() goForward: ƒ goForward() push: ƒ push(path, state) replace: ƒ replace(path, state) location: pathname: "/about" search: "" state: undefined match: params: { } path: "/about" url: "/about"
4、NavLink使用与封装
NavLink可以
实现路由链接的高亮
,通过activeClassName指定样式名
,未点击没效果封装
//封装示例 export default class MyNavLink extends Component { render() { return ( <NavLink activeClassName="atguigu" {...this.props}/> ) } }
- 使用与调用
{/* 在React中靠路由链接实现切换组件--编写路由链接 */} <MyNavLink to="/about">About</MyNavLink> <MyNavLink to="/home">Home</MyNavLink>
5、Switch的使用
1.通常情况下,path和component是一一对应的关系。
2.Switch可以提高路由匹配效率(单一匹配) ---- 即匹配到一个后将不再往下匹配
<Switch> <Route path="/about" component={About}/> <Route path="/home" component={Home}/> <Route path="/home" component={Test}/> </Switch>
6、解决多级路径刷新页面样式丢失的问题
1.public/index.html 中 引入样式时不写 ./ 写 / (常用)
2.public/index.html 中 引入样式时不写 ./ 写
%PUBLIC_URL%
(常用,但只在react中
有效果)3.使用HashRouter (不常用)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>react脚手架</title> <!-- 方法二 --> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <!-- 方法一 --> <link rel="stylesheet" href="/css/bootstrap.css"> </head> <body> <div id="root"></div> </body> </html>
7、路由的严格匹配与模糊匹配
默认使用的是模糊匹配
开启严格匹配:<Route
exact
path=“/about” component={About}/>正常路由建议加exact, 动态路由因为路径不固定, 不能加exact
{/* 添加个人页的动态路由用于传值 */} <Route path="/user/:title" component={User} />
8、Redirect的使用
一般写在所有路由注册的
最下方
,当所有路由都无法匹配时
,跳转到Redirect指定的路由具体编码:
<Switch> <Route path="/about" component={About}/> <Route path="/home" component={Home}/> <Redirect to="/about"/> </Switch>
9、路由跳转
声明式导航:link标签跳转
编程式导航:通过JS代码来实现页面跳转
this.props.history.push()
10、路由传值
Ⅰ-url拼接传值(麻烦,不推荐使用)
//编程式导航
this.props.history.push('/user?title='+title)
- 路由链接(携带参数):
<Link to='/demo/test?name=tom&age=18'}>详情</Link>
- 注册路由(
无需声明
,正常注册即可):<Route path="/demo/test" component={Test}/>
- 接收参数:this.props.location.search
- 备注:获取到的search是
urlencoded编码字符串
,需要解析-------------------------------发送参数:父组件---------------------------------------------- <div> {/* 向路由组件传递search参数 */} <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> <hr /> {/* search参数无需声明接收,正常注册路由即可 */} <Route path="/home/message/detail" component={Detail}/> </div> --------------------------------接受参数:子组件----------------------------------------------------------- export default function User (props){ return <div className="user"> <h3>路由url拼接传值: {decodeURI(props.location.search)}</h3> <h3>动态路由传值: {props.match.params.title}</h3> <h3>自定义对象传值: {props.location.data && props.location.data.title}></h3> </div> }
Ⅱ-动态路由(友好型url)传值
//编程式导航
this.props.history.push('/user/'+title)
路由链接(携带参数):
<Link to='/demo/test/tom/18'}>详情</Link>
注册路由(声明接收):
<Route path="/demo/test/:name/:age" component={Test}/>
接收参数:this.props.match.params
-------------------------------发送参数:父组件---------------------------------------------- <div> {/* 向路由组件传递params参数 */} <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> <hr /> {/* 声明接收params参数 */} <Route path="/home/message/detail/:id/:title" component={Detail} /> </div> --------------------------------接受参数:子组件----------------------------------------------------------- const {id,title} = this.props.match.params
Ⅲ-自定义对象传值
//编程式导航
this.props.history.push({
pathname: "/user",
data: { title }
})
- 路由链接(携带参数):[
<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
]- 注册路由(无需声明,正常注册即可):[
<Route path="/demo/test" component={Test}/>
]- 接收参数:this.props.location.state
- 备注:使用
BrowserRouter
刷新才可以保留住参数
,使用HashRouter
刷新后state将会没有history
来保存参数- 子组件接受参数时
const {id,title} = this.props.location.state || {}
,后面添加||{}
是防止使用HashRouter
后state为undefined时报错-------------------------------发送参数:父组件---------------------------------------------- <div> {/* 向路由组件传递state参数 */} <Link to={{pathname:'/home/message/detail',date:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link> <hr /> {/* state参数无需声明接收,正常注册路由即可 */} <Route path="/home/message/detail" component={Detail}/> </div> --------------------------------接受参数:子组件----------------------------------------------------------- // 接收date参数,后面添加`||{}`是防止使用`HashRouter`后date为undefined时报错 const {id,title} = this.props.location.date || {}
Ⅳ-对比区别
1, url路径传值 优点: 传值简单 缺点: 取值是url编码后的字符串,解析麻烦
2, 动态路由传值 优点: 取值方便 缺点: 配置麻烦
3, 自定义对象传值 优点: 传值取值简单方便 缺点: 网页刷新数据会丢失,需要结合storage
总结, 建议使用动态路由传值
11、编程式路由导航
- -this.props.history.push()
将历史记录压入栈
- -this.props.history.replace()
替代栈位置,即不会产生历史记录
- -this.props.history.goBack()
回退一格
- -this.props.history.goForward()
前进一格
- -this.props.history.go()
前进或者后退n格(根据传入的数字正负数)
12、withRouter的使用
- withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
- 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> ) } } export default withRouter(Header)
13、BrowserRouter与HashRouter的区别
备注:HashRouter可以用于解决一些路径错误相关的问题。即在
问题6
中引入文件时可以不进行路径修改
Ⅰ-底层原理不一样:
- BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
但一般来说都用的这个
- HashRouter使用的是URL的哈希值。
Ⅱ-path表现形式不一样
BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
HashRouter的路径包含#,例如:localhost:3000/#/demo/test
Ⅲ-刷新后对路由state参数的影响
BrowserRouter没有任何影响,因为state保存在history对象中。
HashRouter
刷新后会导致路由state参数的丢失!!!