导航守卫
导航守卫:当离开一个页面,进入另一个页面时,触发的事件
history对象的两个属性(listen,block)
-
listen:添加一个监听器,监听地址的变化,当地址发生变化时候,会调用传递的函数
- 参数:是一个函数,运行时间点:发生在即将跳转到新页面时
- 函数本身有两个参数;
- 参数1:location,记录当前地址信息;
- 参数2:action,一个字符串,表示进入该地址的方式(POP,PUSH,REPLACE)
- POP:出栈
a. 通过浏览器后退、前进;
b. 调用history.go
c. 调用history.goBack
d. 调用history.goForward - PUSH:入栈
a. 点击超链接,本质上调用history.push,往栈中加入 - REPLACE:替换
- history.replace
- POP:出栈
- 参数:是一个函数,运行时间点:发生在即将跳转到新页面时
-
block:
- 设置一个阻塞,参数是一个字符串,当页面发生跳转时候,会进入阻塞,并将阻塞消息传递到路由根组件的getUserConfirmation方法的第一个参数
- 也可以是一个函数,返回一个字符串(函数有两个参数,第一个是location地址信息,第二个是action跳转方式)
路由根组件
- getUserConfirmation
- 参数:是一个函数
- 参数1:history.block传递的阻塞消息
- 参数2:回调函数,调用该函数并传递true,则表示进入到新页面,否则不做任何操作
- 参数:是一个函数
代码实例:
封装的RouteGuard顶级路由,有监听和阻塞的方法,代替Router
import React, { Component} from 'react'
import { BrowserRouter as Router, withRouter } from 'react-router-dom'
let preLocation, newLocation, action,unBlock,unListen //将获取的旧地址,新地址,跳转方式,取消阻塞方法、监听方法保存在全局方便下面RouteGuard组件传递
/**
* // 创建一个辅助函数,获取history,因为RouteGuard导出引用为最顶级,获取不到history上下文
*/
class _GetHistory extends Component {
componentDidMount() {
// 调用Router上下文的history.block创建阻塞
unBlock= this.props.history.block((location, act) => {
preLocation = this.props.location
newLocation = location
action = act
return ""
})
// 调用Router上下文的history.listen创建监听
unListen=this.props.history.listen((location,action)=>{
this.props.onChange(this.props.location,location,action)
})
}
componentWillUnmount(){
unBlock() //取消阻塞
unListen() //组件销毁取消监听
}
render() {
return null
}
}
// 将普通组件用内置的withRouter包装,即可获取Router上下文
const GetHistory = withRouter(_GetHistory)
/**
* 封装组件,包含Router的所有特性,并且能接收props方法
*/
class RouteGuard extends Component {
handleConfirm = (msg, callBack) => {
if (this.props.onBeforeChange) {
this.props.onBeforeChange(msg, preLocation, newLocation, action, callBack,unBlock)
}else{
callBack(true)
}
}
render() {
return (
<Router getUserConfirmation={this.handleConfirm}>
<GetHistory onChange={this.props.onChange}/>
{this.props.children}
</Router>
)
}
}
// 默认导出
export default RouteGuard
使用封装的顶级路由 RouteGuard
import React from 'react'
import { Route, NavLink } from 'react-router-dom'
import RouteGuard from './RouteGuard'
function A() {
return (
<div>
<h1>A组件</h1>
</div>
)
}
function B() {
return (
<div>
<h1>B组件</h1>
</div>
)
}
export default function App() {
return (
<div>
{/* 需要阻塞就填写属性onBeforeChange */}
<RouteGuard //写在最顶级代替Router
onBeforeChange={(msg, preLocation, newLocation, action, callBack,unBlock) => {
console.log(
`阻塞:从${preLocation.pathname}跳转到${newLocation.pathname},跳转方式${action}`
)
unBlock() //阻塞一次就取消阻塞
callBack(false) //回调函数为true就不阻塞放行跳转,false就阻止跳转
}}
onChange={(preLocation,newlocation,action)=>{
console.log(`listen:从${preLocation.pathname}到${newlocation.pathname}+${action}`);
}}
>
<ul>
<li>
<NavLink to="/a">A组件</NavLink>
</li>
<li>
<NavLink to="/b">B组件</NavLink>
</li>
</ul>
<Route exact path="/b" component={B} />
<Route exact path="/a" component={A} />
</RouteGuard>
</div>
)
}