一、路由的使用
- 安装
npm install react-router-dom
- 在原生中使用a标签实现跳转,在react中根据路由连接实现切换组件
- App标签的最外层包裹一个BrowseRouter或者HashRouter标签
import { Link,Route } from 'react-router-dom'
<Link className="list-group-item" to="/home">Home</Link>
<Link className="list-group-item" to="/about">About</Link>
<!-- 内容展示 -->
<Route path='/home' component={Home}></Route>
<Route path='/about' component={About}></Route>
import { BrowserRouter } from 'react-router-dom';
<!-- 最外层包裹一层BrowserRouter标签 -->
<BrowserRouter>
<App />
</BrowserRouter>
二、路由组件和一般组件的区别
- 写法不同:
一般组件:<Demo/>
路由组件:<Route path="/demo" component={Demo}/>
- 存放位置不同:
一般组件: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"
三、NavLink
- 当使用NavLink而不是Link时,点击哪个按钮,className中就会默认追加一个active属性
- NavLink中可以通过activeClassName来指定追加的属性名
<NavLink activeClassName="peiqi" className="list-group-item" to="/home">Home</NavLink>
<NavLink className="list-group-item" to="/about">About</NavLink>
四、NavLink的封装
- 如果页面中需要多个NavLink标签,此时页面中会出现许多的冗余部分,如样式等,那么可对NavLink进行一层封装,将公共的部分内容封装起来,得到一个MyNavLink标签,该标签中内容即为这些标签中不同的内容
- MyNavLink与NavLink的形式保持一致,那么如何将标签体中内容传递给NavLink呢?NavLink中内置了一个children属性,该属性的属性值即为标签体中的内容
<!-- 封装的NAVLink内容 -->
<NavLink activeClassName="peiqi" className="list-group-item" {...this.props}/>
<!-- 对封装后得到的MyNavLink的使用 -->
<MyNavLink to="/about">About</MyNavLink>
<!-- 相当于NavLink中的如下用法 -->
<!--<NavLink activeClassName="peiqi" to="/home" className="list-group-item" children="Home"/>-->
<MyNavLink to="/home">Home</MyNavLink>
- 使用{…this.props}可以避免当MyNavLink中一次性要传递多个props时造成NavLink中接收过于麻烦的情况
标签体内容是一个特殊的标签属性,通过this.props.children可以获取到标签体的内容
五、Switch的用法
- 在使用路由时,如果存在多个路由路径相同,则此时对用的路由组件都会展示,那么这样会导致一个效率问题。当代码在执行时,存在多个相同路径,不同路由组件时,会在找到第一个后,继续向下查找有没有相同路径的路由组件,这样会导致代码的效率问题
- 使用Switch标签可以解决这个问题,在所有的路由组件外包裹一层Switch标签,此时,当匹配到第一个路由组件时,就不会继续再向下进行匹配
import { NavLink, Route, Switch } from 'react-router-dom'
<Switch>
<Route path='/about' component={About}></Route>
<Route path='/home' component={Home}></Route>
<Route path='/about' component={A}></Route>
<Route path='/about' component={B}></Route>
<Route path='/about' component={C}></Route>
</Switch>
- 总结:通常情况下,path和component是一一对应的关系,Switch可以提高路由匹配效率(单一匹配)
六、解决样式丢失的问题
- 当页面中的路由路径是多级的结构时,此时一刷新页面,就会导致页面中的样式丢失问题:页面中使用bootstrap.css样式时,当页面处于多级路由的情况下,点击刷新,此时浏览器再次返回的页面没有bootstrap.css样式
- 导致原因:当路径存在问题时,会直接将public文件下中的index.html中的内容返回,导致样式丢失
- 解决方法:
方法一:
<link rel="stylesheet" href="./bootstrap.css"> 改为: <link rel="stylesheet" href="/bootstrap.css"> 去掉了.,.表示当前文件下
方法二:
<link rel="stylesheet" href="./bootstrap.css"> 改为: <link rel="stylesheet" href="%PUBLIC_URL%/bootstrap.css"> %PUBLIC_URL%表示public绝对路径
方法三:将BrowserRouter改为HashRouter
其中方法一和方法二是常用方法,且方法二只适用于React脚手架中使用
七、路由的模糊匹配和严格匹配
- 模糊匹配(
默认
)
- to中的内容要包含path,且path中的内容必须是在第一个,否则当第一个内容不匹配时,则不会在对后面的内容进行匹配
- 默认是模糊匹配
- 严格匹配
- 在Route标签中添加exact={true}属性,此时即开启严格匹配模式,要求to和path中的内容一致
- 也可以直接使用exact
- 不要随便开启严格匹配,需要再开,有时候开启会导致无法继续匹配二级路由
<Route exact={true} path='/about' component={About}></Route> <Route exact path='/about' component={About}></Route>
八、Redirect的使用
<Switch>
<Route exact={true} path='/about' component={About}></Route>
<Route path='/home' component={Home}></Route>
<Redirect to="/home"/>
</Switch>
- Redirect放在所有路由注册的后面,当所有的路由都没有匹配成功时,跳转到Redirect指定的路由
- 可实现当页面一加载时,默认路由选中的效果
九、向路由组件传递params参数
<!-- 利用ES6中的模板字符串传递params参数 -->
<!-- 路由链接——携带参数 -->
<Link to={`/home/messages/detail/${messageOj.id}/${messageOj.title}`}>{messageOj.title}</Link>
<!-- 接收参数,通过:XXX的形式 -->
<!-- 注册路由——声明参数 -->
<Route path="/home/messages/detail/:id/:title" component={Detaildata}/>
- 注意:这里的传递给Detaildata组件中的params参数,在Detaildata中通过this.props.match.params获得
- 可以利用解构
{id,title} = this.props.match.params
获得传递的id和title
十、向路由组件传递search参数
- 与传递params参数相比,search参数的接收更容易,但是获得确更麻烦。params参数获得的是一个已经整理好的对象,但是search却是一个字符串,需要再进行加工整理
- 传递参数:
<Link to={`/home/messages/detail/?id=${messageOj.id}&title=${messageOj.title}`}>{messageOj.title}</Link>
- 接收参数:不用像search那样声明接收参数
<Route path="/home/messages/detail" component={Detaildata}/>
- 整理参数:用于search参数传递是urlencoded编码字符串(
?key=value&key=value
),因此还需要进行特殊整理
- 引入querystring库,该库时react脚手架已经下载好的,直接引用即可
import qs from 'querystring' 该库中有两个函数,一个是stringify:将对象整理成key=value&key=value的形式 如:{name:'Tom', age: 18}通过qs.stringify()处理变成name=Tom&age=18 一个是parse:将字符串解析成对象的形式
通过this.props.location.search.slice(1)
获取传递的search参数,注意这里的slice(1)是为了去掉字符串前面的?
<!-- 传递参数 -->
<Link to={`/home/messages/detail/?id=${messageOj.id}&title=${messageOj.title}`}>{messageOj.title}</Link>
<!-- 接收参数(不用声明接收,正常注册路由即可) -->
<Route path="/home/messages/detail" component={Detaildata}/>
//处理参数
const {data} = this.state
const str = this.props.location.search.slice(1)
const {id, title} = qs.parse(str)
十一、向路由传递state参数
- 与前面的两种参数相比,传递state参数时,搜索栏中不显示携带的信息,即信息被隐藏
- 路由链接——携带参数
<Link to={{pathname:'/home/messages/detail',state: {id:messageOj.id,title:messageOj.title}}}>{messageOj.title}</Link>
以对象的形式传递
- 注册路由(无需声明,正常注册即可)
<Route path="/home/messages/detail" component={Detaildata}/>
- 接收参数:
this.props.location.state
- 当向路由传递state参数时,刷新也可以保留住参数
十二、如何开启replace模式
- 当路由链接开启replace模式时,点击该链接,此时栈顶的路由记录会被替换掉
- 如何开启:在路由链接中添加replace={true}或者replace属性
十三、编程式路由导航
history:
go: ƒ go(n)
goBack: ƒ goBack()
goForward: ƒ goForward()
push: ƒ push(path, state)
replace: ƒ replace(path, state)
- replace的实现
1.replace和传递params参数
//定义 onClick={() => this.clickReplace (id,title)} //实现 clickReplace = (id,title) => { this.props.history.replace('/home/messages/detail/${id}/${title}');}
- replace和传递search参数
//定义 onClick={() => this.clickReplace (id,title)} //实现 clickReplace = (id,title) => { this.props.history.replace('/home/messages/detail/?id=${id}&title=${title}');
- replace和传递state参数:push: ƒ push(path, state)
//定义 onClick={() => this.clickReplace (id,title)} //实现 clickReplace = (id,title) => { this.props.history.replace('/home/messages/detail',{id,title});
- push的实现
- 和replace使用过程一样,但是使用this.props.history.push()
- 其他:
this.props.history.goBack()——后退
this.props.history.goForward()——前进
this.props.history.go(num):num为正时,表示前进,为负时,表示后退
十四、withRouter
- 当在一般组件中要使用路由组件中的一些特有的API时,如:在一般组件中通过this.props.history来进行调用时,由于路由组价和一般组件中的this.props是不一样,此时会报错。那么如何解决这个问题呢?利用withRouter可以解决
- 作用:withRouter可以加工一般的组件,让一般组件具备路由组件所特有的API。withRouter是个函数,接收的参数为一般组件,用于解决在一般组件中使用路由组件中的API的问题。其返回值是一个新的组件
//1.引入
import {withRouter} from 'react-router-dom'
//2.定义一般组件
class XXX extends React.Component {
}
//3.将一般组件作为参数传入
//一般组件:<XXX />
export default withRouter(XXX)
十五、BrowserRouter和HashRouter的区别
- 底层原理不一样:
- BrowserRouter使用的是H5的history API,不兼容IE9及以下版本
- HashRouter使用的是URL的哈希值
- path表现形式不一样:
- BrowserRouter的路径中没有#
- HashRouter的路径包含#
- 刷新后对路由state参数的影响:
- BrowserRouter没有任何影响,因为state保存在history对象中
HashRouter刷新后会导致路由state参数的丢失
- HashRouter可以用于解决一些路径错误相关的问题