每个vue单文件组件中,可以加入三种route navigation guards(导航守卫钩子):
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
比较常用的是beforeRouteEnter和beforeRouteLeave,这里总结下项目中遇到的应用场景。
组件的路由守卫beforeRouteEnter
和created和mounted生命周期冲突
beforeRouteEnter(to, from, next) {
next((vm) => {
})
},
beforeRouteEnter(to, from, next) {
next(vm => {
const settings = cloneDeep(vm.userConfig);
vm.setttingConfig = settings;
});
},
1.keep-alive
比较常见的一种应用场景就是,当前页面是数据列表页并且开启了缓存,跳转到其他子页面再跳转回来时,需要根据不同的页面或参数来判断是否重新加载列表页的数据。
有一种方法就是给列表页的路由配置meta字段——路由元,设置一个refresh属性,并在activated钩子里做对应处理。
{
path: "/bookList",
name: "bookList",
component: resolve => require(["@/views/book/List"], resolve),
navbarOption: "书籍列表",
meta: {
keepAlive: true, // 组件缓存
refresh: false // activated钩子触发时是否重新加载数据
}
},
2.组件缓存
代码中用到了sessionStorage、localStorage,但有时候走了一圈流程后需要重置数据,就可以在beforeRouteEnter或beforeRouteLeave处理这些缓存。
3.有个项目用到了高德地图AMap,AMap插件在调用api时,会自动抓取当前页面路径作为参数appname的值,但有时候抓取的却是上一个页面的路径,而如果上一个页面的路径太长的话,这请求就直接413了。实际上,地图页面路径其实并不长,所以这里在渲染地图之前,刷新页面,这样AMap抓取的页面路径就是当前页面路径了。
组件的路由守卫beforeRouteLeave
1.离开本路由前需要重置样式。
2.代码中用到了sessionStorage、localStorage,但有时候走了一圈流程后需要重置数据,就可以在beforeRouteEnter或beforeRouteLeave处理这些缓存。
3.离开本路由前显示确认框:确认离开本页面。
4.从本页面返回时,不是回到上一个页面,而是需要指定别的页面,,那么就要在beforeRouteLeave方法里处理,最后一定要加上next();
<template>
<div class="test_box">
组件内部导航守卫钩子
</div>
</template>
<script>
let map, needReload = false; // 需要重新加载页面
export default {
data() {
return {
mapfromlng: 0,
mapfromlat: 0,
mapFromcity: '北京'
}
},
methods: {
initData(){
console.log('initData');
},
initmap(){
if(needReload) {
window.location.reload()
}
map = new AMap.Map("container", {
resizeEnable: true,
zoom: 11,
center: [this.mapfromlng, this.mapfromlat],
mapStyle: "amap://styles/macaron"
});
// 通过插件获取LEAST_TIME
AMap.plugin(["AMap.Transfer"], () => {
let transOptions = {
city: this.mapFromcity, //公交城市
policy: AMap.TransferPolicy.LEAST_TIME //乘车策略
};
transfer = new AMap.Transfer(transOptions); //构造公交换乘类
//根据起点、终点坐标查询公交换乘路线
transfer.search(new AMap.LngLat(this.mapfromlng, this.mapfromlat), new AMap.LngLat(this.maptolng, this.maptolat), (s, res) => {
if (res.plans && res.plans.length > 0) {
// to do ...
}
});
});
}
},
// 路由访问时
beforeRouteEnter(to, from, next) {
// 1.在meta中,存储refresh字段,用来判断是否需要重新加载数据
if(from.name === 'refund' || from.query.fromDetail === 1){
to.meta.refresh = true;
}
// 2.重置缓存
window.sessionStorage.setItem('fromPhaseOne',0);
// 3.需要刷新当前页面
if (from.fullPath.indexOf('index') != -1 && from.fullPath.indexOf('source') != -1) {
needReload = true;
}
next();
// 或者,在next()回调里访问this
// next(vm => {
// vm 就是当前组件的实例相当于this,所以在 next 方法里可以把 vm 当 this 来用了。
// console.log('beforeRouteEnter-this',vm);
// });
},
// 路由更新时
beforeRouteUpdate(to, from, next) {
// 以动态路由的方式(如`/foo/:id`),再次访问到当前组件时,调用beforeRouteUpdate
// 可以访问组件实例 `this`
next();
},
// 路由离开时
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
// 1.回滚样式
document.querySelector(".router-bg").style.cssText = "";
// 2.重置缓存
window.sessionStorage.setItem('fromPhaseTwo',0);
// 3.显示离开当前页面的确认框
this.$confirm({title:'订单尚未支付,确定离开?'});
// 4.跳转到指定路由或页面
if (["/pay"].indexOf(to.path) > -1 && this.$env.isMiniProgram) {
next(false);
// 跳转到小程序的某个页面
wx.miniProgram && wx.miniProgram.redirectTo({
url: "/page/mine/mine"
});
} else {
// 跳转到指定页面
this.$router.push({
path: "/detail",
query: {status:2}
});
next(true);
}
// next();
},
mounted () {
this.initmap();
},
activated () {
// 需要刷新页面
if (this.$route.meta.refresh) {
this.$route.meta.refresh = false;
this.initData();
}
},
}
</script>